Built with R version 4.4.2.

1 Introduction

The purpose of this document is to make open and share-able the research methods used for my dissertation on nearshore fish communities in Alaska working towards a PhD in marine biology at the University of Alaska Fairbanks. Here, I cover second-stage steps of the data preparation for my second and third chapters concerning spatial and temporal distributions of nearshore fishes across the state. This and other files can be accessed via the Kachemak Bay National Estuarine Research Reserve’s github repo.

In this document I share exploratory data analyses conducted on the NOAA Nearshore Fish Atlas (NFA) database. The NFA database can be found here, https://alaskafisheries.noaa.gov/mapping/sz/. Namely, this document contains the steps taken after cleaning/wrangling raw data. In particular I produce various visualizations of the data in space and time. Part I of these data preparation steps can be accessed at https://rpubs.com/chguo1/1188614, and the resulting data objects are loaded below (file “nfaa_1.rda”).

1.1 Set up

Load required packages, define directory, set options, source/load files:

# Packages
library(tidyverse)
library(lubridate)
library(here)
library(leaflet)
library(RColorBrewer)
library(vegan)
library(ggsignif)
library(ggpubr)

# Directory
wd = here()
dirs = wd %>% list.files() %>% str_subset(pattern = "^README|^LICENSE|.md$|.Rproj$", negate = TRUE)
for (i in seq_along(dirs)) {
  name = str_replace_all(dirs[i], "^", "dir.")
  path = str_replace_all(dirs[i], "^", str_c(wd, "/"))
  assign(name, path)
  rm(name, path, i)
}

# Options

# Source/Load
load(file.path(dir.data, "nfaa_1.rda")) # wrangled data

1.2 Background and objectives

Based on my own research and related literature, I can broadly interpret these beach seine data in a spatiotemporal context. Depending on when (time of year) and where (location and habitat), I have a general structure in mind of the diversity of the community. Depending on who’s there, I have a rough guess of the relative abundance of each community member (at least for the more commonly caught ones). My hope with working with the NFA data is that this broad understanding can be formally tested with inference and statistics, and that more informative research questions can be answered.

Findings from other nearshore fish researchers largely agree that seasonality (or some related environmental condition) is a strong predictor of community or species presence. Interannual differences can exhibit wide variability and should be accounted for whenever possible. And at larger time-scales (e.g., decadal), communities exhibit changes which may relate to regime shifts occurring more broadly than the nearshore.

Spatially, large-scale (regional) effects appear to be as or more important than sub-regional or local-scale effects. However, many studies also find significant relationships in community response at these smaller scales. Likely, the most appropriate spatial consideration depends on the question being asked. So maybe a more appropriate question to ask of the NFA data is if there any significant spatial scales discernible in the data, and also how should we address those scales in future research, such as studies on subsets of the taxa or habitat management considerations.

I’ll start by exploring the structure of our ‘visits’ dataframe, and then I’ll move on to visualizing the information derived from out ‘catch’ dataframe.

2 Exploring visit data

2.1 Summary of visits

Remember that in the data wrangling stage, we created a new sample identifier based on site and date which we called VisitID. Let’s take a look at the variables associated with each VisitID:

glimpse(visits)
## Rows: 1,867
## Columns: 7
## $ VisitID    <chr> "1_2001-07-24", "1_2002-03-25", "1_2001-04-26", "1_2002-07-…
## $ Replicates <int> 5, 7, 4, 4, 5, 3, 4, 2, 6, 1, 2, 2, 6, 4, 4, 4, 4, 3, 2, 2,…
## $ Date       <date> 2001-07-24, 2002-03-25, 2001-04-26, 2002-07-24, 2003-03-22…
## $ Lat        <dbl> 58.56626, 58.56296, 58.56408, 58.56755, 58.55804, 58.56858,…
## $ Lon        <dbl> -134.9105, -134.9082, -134.9137, -134.9133, -134.9102, -134…
## $ MeshSize   <dbl> 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2,…
## $ Cluster    <fct> 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 326,…

During the wrangling stage, I decided that Replicates and MeshSize should be the main covariates that needed consideration. At this point they are classed as integers/numbers, but we will probably want them to be factors instead. Cluster is a byproduct of clustering some sites together, so it may not be needed if we’re using Lat/Lon as our primary explanatory variable. Still, it could be a useful grouping factor later on. Date will likely be mutated into multiple additional periods (day of year, month, year) to see if any of those factors are useful in explaining fish data. We’ll address edits to these variables as they come up in our exploration.

2.2 Spatial distribution

leaflet(visits) %>% 
  addTiles(options = tileOptions(minZoom = 3.5,
                                 zIndex = 0.5)) %>%
  setView(lat = 65, lng = -152, zoom = 3.5) %>%
  addSimpleGraticule(interval = 5) %>%  
  addCircleMarkers(lng = ~Lon, lat = ~Lat,
                   stroke = FALSE,
                   popup = ~VisitID,
                   clusterOptions = markerClusterOptions())

In the map above we can view all of our samples from across Alaska. Leaflet options are nice because you can optionally group samples on the map and show a boundary polygon of the area they cover when you hover over their icon. At the minimum zoom level (3.5), we see the largest group spanning nearly all of Southeast Alaska, followed by a group in Southcentral that covers Prince William Sound, Cook Inlet, and the northern half of Kodiak Island. The third largest group forms a much smaller polygon area around Utqiagvik. From there, we see even smaller groups from the Eastern Beaufort Sea around Kaktovik, the Bering Strait and Southern Chukchi Sea near Kotzebue, and Bristol Bay. There are also two groups from the Alaska Peninsula and Aleutian Islands, one focused around Adak and another spanning from Sand Point to Unalaska. We can see how subsets of the samples change by zooming in. When there are single samples in view, hovering over those will tell us its VisitID name.

Obviously, this visualization of the data is not perfect and pretty rough- note that the groups are formed by the overlap of samples based on pixel radius (10). For example, the polygon of samples from Bristol Bay at the minimum zoom level actually crosses the Alaska Peninsula to include a sample from Aghiyuk Island. Although, the map is useful in gaining a general understanding of the existing clusters of samples within the NFA database.

2.3 Regions

We may want to define a spatial factor based on these rough groupings as a starting place to see if the smaller, more isolated groups should be lumped with other groups or not. Actually, the NFA already has a Region classifier per site, but the reason I do not want to use it is because they linked Region to SiteID. When we created our new VisitID, some samples now contained two Region labels- these were mostly cases from around Utqiagvik where some were labelled as Chuckchi and others as Beaufort but actually occurred on the same day and within a very short distance of each other.

Instead of using the the given regional classes, let’s just make our own variable called ‘Region’ and add it to the our visits df:

# Start with events so that we can make use of Location info for unique cases,
regions = events %>%
  select(EventID, VisitID, Lat, Lon, Location) %>%
  mutate(Region = case_when(Lat > 69 & Lat < 80 & Lon > -150 & Lon < -140 ~ "Beaufort East",
                            Lat > 69 & Lat < 80 & Lon > -160 & Lon < -150 ~ "Chukchi/Beaufort",
                            Lat > 65 & Lat < 69 & Lon > -170 & Lon < -160 ~ "Chukchi South",
                            Lat > 57 & Lat < 60 & Lon > -165 & Lon < -155 ~ "Bristol Bay",
                            Lat > 50 & Lat < 55 & Lon > -180 & Lon < -175 ~ "Aleutians Adak",
                            Lat > 50 & Lat < 55 & Lon > -170 & Lon < -165 ~ "Aleutians Unalaska",
                            Lat > 55 & Lat < 65 & Lon > -155 & Lon < -145 ~ "GOA Southcentral",
                            Lat > 53 & Lat < 61 & Lon > -148 & Lon < -130 ~ "GOA Southeast"))

# Check which samples we missed,
filter(regions, is.na(Region))
## # A tibble: 7 × 6
##   EventID VisitID           Lat   Lon Location                            Region
##     <dbl> <chr>           <dbl> <dbl> <chr>                               <chr> 
## 1    6635 1564_2006-06-22  52.7 -171. Yunaska Island                      <NA>  
## 2    6636 1565_2006-07-26  56.2 -157. Semidi Islands, Aghiyuk Island      <NA>  
## 3    6637 1566_2006-07-31  55.1 -160. Shumagin Islands, Bendel Island     <NA>  
## 4    6638 1566_2006-07-31  55.1 -160. Shumagin Islands, Bendel Island     <NA>  
## 5    6639 1568_2006-07-31  55.1 -160. Shumagin Islands, Spectacle Island  <NA>  
## 6    6640 1569_2006-07-31  55.1 -160. Shumagin Islands, Nagai Island, Mi… <NA>  
## 7    6641 1569_2006-07-31  55.1 -160. Shumagin Islands, Nagai Island, Mi… <NA>
# Let's address those using Location,
regions = mutate(regions,
       Region = case_when(!is.na(Region) ~ Region,
                          is.na(Region) & str_detect(Location, "Yunaska") ~ "Aleutians Yunaska",
                          is.na(Region) & str_detect(Location, "Aghiyuk") ~ "Aleutians Aghiyuk",
                          is.na(Region) & str_detect(Location, "Shumagin") ~ "Aleutians Shumagin"))

# Check again (should be 0),
filter(regions, is.na(Region)) %>% nrow()
## [1] 0

Now let’s add Region as a factor to our visits df, and show it on a map. Since we’re manipulating our data objects again, let’s also rename visits so that we can keep track of our changes.

# Call our wrangled df version visits.0 and remove the non-version 'visits' if it's there,
if ("visits" %in% ls()) assign("visits.0", visits)
if ("visits" %in% ls()) rm(visits)

# Make Region a factor and join by VisitID,
visits.1 = regions %>%
  select(VisitID, Region) %>%
  distinct() %>%
  mutate(Region = as.factor(Region)) %>%
  left_join(visits.0, ., by = "VisitID")

# Function for regional palette
palette.region = colorFactor(palette = brewer.pal(n = visits.1$Region %>% n_distinct(),
                                                  name = 'Spectral'),
                             domain = factor(visits.1$Region))

# Map
leaflet(visits.1) %>% 
  addTiles() %>%
  addCircleMarkers(lng = ~Lon, lat = ~Lat,
                   color = ~palette.region(Region),
                   fillColor = ~palette.region(Region),
                   popup = ~paste(Region, VisitID),
                   stroke = FALSE) %>%
  addLegend(position = "topright",
            pal = palette.region, values = ~Region,
            title = "Region",
            opacity = 0.75)

Like we saw before, the majority of our samples are located in the Gulf of Alaska (GOA), namely Southeast (SEAk) and Southcentral (SCAK). If we were to look at differences in catach in the GOA, it’d be cool if we could include the Aleutian samples too. Obviously, we’ll want to address those few instances from Aghiyuk, Shumagin, and Yunaska, and ideally we aggregate them into one or two groups. We also see relatively small sample sizes from Bristol Bay and from East Beaufort, which may or may not be prohibitive in conducting meaningful tests. One other consideration is the couple of samples along the Bering Strait coast which are lumped together with a larger concentration of samples from South Chukchi.

Some of our first analyses should see if the more isolated samples are different from the other samples. If not, then we can aggregate. If yes, then we should report any significant tests.

2.4 Temporal distribution

Next we’ll want to take a look at how our samples distribute throughout various time periods. This will give us a good idea of how well our samples may or may not overlap- particularly, we’ll want to see overlaps in years and months for better comparisons of the catch data.

# First create a df specifically containing at time variables
times = visits.1 %>%
  select(VisitID, Date) %>%
  mutate(Year = year(Date),
         Month = month(Date, label = TRUE),
         Week = week(Date),
         Day = yday(Date))

# Function to generate frequency plots for temporal vars
plot_times = function(x) {
  times %>%
    filter(Year > 1980) %>%
    count(!!sym(x)) %>%
    distinct() %>%
    ggplot(., aes(x = !!sym(x), y = n)) +
    geom_col() +
    labs(x = NULL, y = NULL,
         title = paste("No. samples per", x, sep = " "),
         subtitle = "w/o data from 1976") 
}

# Generate plots
map(names(times)[3:6], plot_times)
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

By year, we see a large variability in number of samples, as well as a lone 1976 year which I recognize to be Blackburn’s dataset from Lower Cook Inlet. That 1976 is an interesting dataset that could be useful for a look at catches over time in that specific area, but it’ll need to be excluded from any other comparisons. The lowest number of samples occur in 2010, 2020, and 2021. We may want to pay close attention to these years in case they show up as outliers. It seems that 1996-2000 is a period of heavy sampling, followed by the mid 2010s and somewhat active year in 2006.

By month, we see an obvious uptick during the summer which makes sense given winter conditions along most of Alaska’s coast (light, ice, etc.). March and October are interesting months because of the potential for impacts on fishes during years with warmer shoulder seasons. November thru February will likely be removed for our purposes. Our key months look to be June, July and August, with possible inclusion of April, May, and September.

It’s interesting if we look at the by-week and by-day graphs, we see a dip in sampling around mid-June/early-July. Not sure why this is- maybe related to more targeting of juvenile salmonids in early June, or maybe so reduced effort around the 4th of July holiday.

2.5 Year & Month by Region

Let’s now see how our samples overlap by Region and Year, and by Region and Month. For these purposes, let’s combine the Aleutians into one group for now, and remove the 1976 data.

Interesting that each region’s samples center on a different year. At a glance, I see the most overlap in 2006 where the Aleutians and both GOA regions look to have similar sample densities, plus there is a smattering of Chukchi/Beaufort sampling too. In 2009, the Bristol Bay samples may be compared with both GoA regions and the Chukchi/Beaufort, although the samples look more sparse across the regions. And in 2013, the Chukchi/Beaufort has good overlap with both GOA regions again. I see nice periods of comparison between SEAK and SCAK, but there is also a concerning difference in yearly distribution of samples between the two regions. Depending on how important year effects appear- we may need to trim the data for better comparisons.

By month, we see that August contains samples from all regions. June is the center for SEAK and the Aleutians, July for SCAK, and August for Chukchi/Beaufort. Best comparisons from this monthly view may be an August (or lumped July + August) comparison of all Regions. Also, a June (or lumped June thru August) comparison of GOA and the Aleutians would be good. And, we should be able to nicely compare SEAK and SCAK from May to September, potentially including April.

For now, we’ll hold off on excluding any of the data. It’ll be better to revisit these considerations after deciding which research questions to tackle, so subsets of the data can be made specific to each one.

2.6 Mesh Size & Replicates

Let’s make similar visuals as before, but now focus on Mesh Size and Replicates in space and time. First, we can re-map the samples to color by Mesh Size and size of points relative Replicates (large dots = more replicates).

I have an issue discerning among the seven different sizes since those warmer colors do not diverge well. Although there are some patterns to make note of: the largest mesh size of 12.7 only occurs in a small area of SEAK, the 10 mm samples similarly only occur with the 12.7 mm samples (likely the Lundstrom et al. 2022 gear comparison), and the smallest size at 3 mm only occurs in Cook Inlet. I don’t see any obvious spatial patterns in Replicates, although this may not be the best view of it.

Let’s see the frequency of samples for both variables:

# Table view
table(visits.1$MeshSize)
## 
##    3  3.2    6  6.4  9.5   10 12.7 
##  436  821  286   35   82   59  148
table(visits.1$Replicates)
## 
##   1   2   3   4   5   6   7   8   9  10  12 
## 665 533 334 142  60  90  19  21   1   1   1

There are more 12.7 mm samples than I would have guessed which is a shame because if they are completely different then we lose a lot of samples. I am wondering if sizes are accurate- I would think that 3 mm and 3.2 mm are effectively similar in practice. I am also wondering if some projects report, say 3 mm instead of 3.2 mm, because of rounding. I would assume that the nets used were manufactured in the US, which would mean that specifications are given in standard not metric. Let’s do a quick check on how typical mesh sizes convert from inches to millimeters.

# Function based on inch to millimeter conversion
in_to_mm = function (x) {
  return(y = 25.4 * x)
}

# Typical mesh sizes in inches
sizes = c((1/8), (1/4), (3/8), (1/2), (5/8), (3/4))

# Convert to millimeters
in_to_mm(sizes)
## [1]  3.175  6.350  9.525 12.700 15.875 19.050

There is obviously some funny rounding happening in the data. I do not see an issue by lumping mesh sizes that are within one millimeter. Even if the nets were actually different by fractions of a millimeter, I don’t think it would affect the selectivity of fishes all that much- especially considering that most of these researchers were capturing fish to be measured to the nearest millimeter.

Let’s see that map again with this in mind:

Much easier to read! I see some concerning patterns we’ll want to investigate further as we go. The majority of samples appear to be using the 3.2 mm size, including both Arctic groups that seem to use it exclusively. There is a large density of 6.4 mm samples in Northern SEAK and throughout the Aleutians. The same issues are visible concerning the two larger mesh sizes. We should do a comparison of 3.2 mm and 6.4 mm to see if there are any significant differences in catch.

With the simpler color scheme, I am also noticing the difference in Replicates a little easier. Just looking at GOA and Aleutian samples, I see that many of the 6.4 mm samples are also low-Replicate samples. Although, many of our samples only contain one replicate so this may just be something I’m seeing and not actually a concern.

Let’s take a look at how these variables in graphical format. I’ll go ahead and aggregate similar mesh sizes and re-classify the both variables as factors, and add in variables for year and month.

visits.2 = mutate(visits.1,
                  # Replicates as an ordered factor
                  Replicates = as.ordered(Replicates),
                  # Combine similar mesh sizes to the tenth decimal
                  MeshSize = case_when(MeshSize < 4 ~ 3.2,
                                       MeshSize > 4 & MeshSize < 7 ~ 6.4,
                                       MeshSize > 7 & MeshSize < 11 ~ 9.5,
                                       MeshSize == 12.7 ~ 12.7) %>%
                    as.ordered()) %>%
  # Add temporal variables
  left_join(select(times, VisitID, Year, Month, Week, Day), by = "VisitID") %>%
  # Week as an ordered factor (month is already an ordered factor)
  mutate(Week = as.ordered(Week))

Our samples are dominated by 3.2 mm mesh size. It looks to have somewhat even distribution among years, but seems to mimic the density of sampling in SEAK and SCAK in the late 90’s, mid 00’s, and mid 10’s. The 6.4 mm size is much more sporadic with many years missing samples. We also see that larger mesh sizes 9.5 mm and 12.7 mm only occur in a handful of years starting 2013. By month, we see similar distributions among the mesh sizes, with most samples occurring in the summer (Jun - Aug) and shoulder months (Apr, May, Sep).

I do not see the yearly distribution of samples differing all that much among replicates. Except that the 6 - 8 replicates tend to occur later in the dataset. I also do not see a difference in how replicates distirbute among months- similar to what we’ve seen that most samples occur in summer and shoulder months.

Last, let’s see a graph of Mesh Size vs Replicates:

Nothing new here really.

2.7 Preparing data for next steps

2.7.1 Spatial aspects

Spatial effects are probably the most unknown to me and could use deeper investigation. We have obvious regional grouping of samples, with a large majority occurring in SEAK and SCAK. There are interesting pockets of data from the Arctic, Bering Sea, and the Aleutians, but how comparable these “regions” are may be complicated by low sample sizes and confounding factors (Mesh Size or Replicates). I think tackling the GoA is the most useful thing to do at the moment since the other areas are much more isolated and densely sampled.

Questions:

  • Basically: how should we treat samples from SEAK, SCAK, and Aleutians?
  • Are there regional effects in the GoA?
  • Do these effects align with current region labels, or is there a more appropriate break point?
  • Can the Aleutian samples be grouped with the GoA, or is it much too different?
  • Are the various Aleutian samples appropriate to aggregate?
  • Similarly, are there appropriate sub-regional groups that can be defined within SEAK and SCAK?
  • What sub-regional groupings make sense? Which, if any, are informative?

After these questions are answered, we can recommend how to treat spatial aspects in the data.

2.7.2 Temporal aspects

Unless we want to do some direct comparisons between 1976 and other years of Kachemak Bay, it just seems too far isolated from the rest of the data to include it in analyses. I will try to address seasonal effects using Day of Year, but move to weeks then months if necessary. We should also keep in mind that April/May and September represent “shoulder” months that are much less sampled compared to June - August period. Some regions may not have samples from shoulder seasons, so reducing the dataset may be required depending on where the comparisons are being made.

Questions:

  • Which of Day, Week, Month is most informative as seasonality?

Recommendations:

  • Remove 1976 data
  • Remove months outside of April - September
  • Year as random effect
  • Seasonality as fixed effect

2.7.3 Mesh Size

Our 3.2 mm samples are the most represented mesh size occurring in all years of data. The 6.4 mm samples are the next most frequent but occur sporadically from 1999-2003, 2006-2008, 2011-2013, and 2017. The other two sizes are the least frequent and occur in later years of the dataset starting in 2013. By month, we see a similar trend as other variables where most samples occur in Jun - Aug no matter the mesh size.

Questions:

  • Is there a significant gear effect among mesh sizes? In particular looking at 3.2 mm vs 6.4 mm

Recommendations

  • Drop 9.5 mm and 10.7 mm sizes (likely confounded by isolated regional effects)
  • Mesh size as fixed effect

2.7.4 Replicates

Something that’s been obvious is the high density of samples with 1 or 2 replicates. I would expect a larger variability in catch response between one/two replicate samples vs three or more replicate samples. There doesn’t seem to be much of a difference in yearly spread of replicates, except when looking at sample with five or more replicates. Similarly by month, we find most of our samples to occur in Jun - Aug no matter the number of replicates.

Questions

  • Can we estimate the number of replicates that results in an informative sample? IOW, is there an ideal number of replicates (e.g., 3) beyond which we do not gain any more meaningful information?

Recommendations

  • Number of replicates as fixed effect
  • Standardize samples by number of replicates, i.e., average catch per visit
  • Standardize samples by another estimate, e.g., sample completeness or species accumulation (if needed)
  • Weight samples by how much information on average each level of Replicates provides (if needed)

2.8 Fixing data objects and clean up

Last thing we’ll is fix our visits data based on our recommendations after EDA. We’ll save an original version of the data in case we want it for future analyses.

# Create a new visits object containing a subset of the full data
visits = visits.2 %>%
  # Filter temporal info: remove year 1976 and months outside of April - September
  filter(Year > 1980) %>%
  filter(Month > "Mar" & Month < "Oct") %>%
  # Filter mesh size: remove 9.5 mm and 10.7 mm
  filter(MeshSize < '9.5') %>%
  # Re-order filtered factors to match reduced levels
  mutate(Month = month(Date) %>% as_factor(),
         Week = week(Date) %>% as.ordered(),
         MeshSize = MeshSize %>% as.character() %>% as.ordered())

# Keep a full visits data object as another object
visits.all = visits.2

# Remove unwanted objects in environment
rm(list = ls()[!ls() %in% c('events', 'catch', 'visits', 'visits.all')])

# Reset directory
wd = here()
dirs = wd %>% list.files() %>% str_subset(pattern = "^README|^LICENSE|.md$|.Rproj$", negate = TRUE)
for (i in seq_along(dirs)) {
  name = str_replace_all(dirs[i], "^", "dir.")
  path = str_replace_all(dirs[i], "^", str_c(wd, "/"))
  assign(name, path)
  rm(path, i)
}

3 Exploring catch data

3.1 Summary of catch

Since we’ve reduced our samples based on earlier EDA, we need to update our catch samples to reflect this. This also requires subsetting the events-level data object.

Similar to our visits object, we’ll create a working version of our catch data but keep the version that contains all info.

Now we have a subsetted catch data, let’s take a look at what’s there:

skimr::skim(catch.0)
Data summary
Name catch.0
Number of rows 116565
Number of columns 10
_______________________
Column type frequency:
character 7
numeric 3
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
Sp_CommonName 0 1.00 7 30 0 185 0
Sp_ScientificName 0 1.00 7 33 0 144 0
Fam_CommonName 0 1.00 4 18 0 33 0
Fam_ScientificName 0 1.00 7 17 0 33 0
LengthType 72266 0.38 2 6 0 5 0
LifeStage 47596 0.59 3 8 0 6 0
Gen_ScientificName 0 1.00 5 15 0 112 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
EventID 0 1.00 4932.27 3013.00 1 3023 4015 7377 10340 ▃▇▁▅▃
Length_mm 10322 0.91 87.30 66.48 4 44 70 107 930 ▇▁▁▁▁
Count 0 1.00 18.07 602.14 1 1 1 1 99997 ▇▁▁▁▁

Looking at our character data, we should go ahead and remove common names simply to reduce clutter. LengthType is not very useful and is missing quite a few observations- we’ll drop this too. We knew LifeStage was an issue when we did our wrangling steps. We can keep it for now, but likely won’t use it til way later. Hopefully, we can infer LifeStage down the road by using the length information.

Let’s add our VisitID variable so we analyse our catch at the sample level (instead of replicate).

catch.1 = catch.0 %>%
  # Add VisitIDs
  left_join(select(events, VisitID, EventID), by = "EventID") %>%
  # Remove unwanted parameters
  select(-c(Sp_CommonName, Fam_CommonName, LengthType)) %>%
  # Tidy parameters
  select(VisitID, EventID,
         Fam_ScientificName, Gen_ScientificName, Sp_ScientificName,
         Count, Length = Length_mm, LifeStage)

3.2 Calculate metrics of catch

3.2.1 Occurrence and rare taxa

Previously in the wrangle step, we defined rare as occurring in less than 0.25% of samples. However, we may start with a more conservative approach to see if removing more rare species is necessary. It makes sense to me to remove species with only 1 or 2 occurrences for now. This is equivalent to removing species occurring in less than 0.15% of samples.

# Create a tibble for species occurrences
sp.occur = catch.1 %>% 
  # For each species within each visit, Presence = 1
  summarise(Presence = n_distinct(Sp_ScientificName), .by = c(VisitID, Sp_ScientificName)) %>%
  # For each species, total the number of presences
  summarise(Occurrence = sum(Presence), .by = Sp_ScientificName) %>%
  # Calculate occurrence as a percentage
  mutate(Perc_Occurrence = round(Occurrence / n_distinct(events$VisitID) * 100, 2)) %>%
  # Add rare category (subject to change)
  mutate(Rare = ifelse(Occurrence < 3, "Yes", "No"))

# Create a tibble for total presences per sample
n.occur = catch.1 %>% 
  # For each species within each visit, Presence = 1
  summarise(Presence = n_distinct(Sp_ScientificName), .by = c(VisitID, Sp_ScientificName)) %>%
  # For each visit, total the number of presences
  summarise(n_sp = sum(Presence), .by = VisitID)

# Create a vector of the rare species
rare.species = filter(sp.occur, Rare == "Yes") %>% pull(Sp_ScientificName)
# Remove rare taxa and update the catch tibble
catch.2 = filter(catch.1, !Sp_ScientificName %in% rare.species)

3.2.2 Average abundance per visit

Because our samples (visits) contain a variable number of replicates (events), I decide to use an averaging method to calculate abundance. Here, we use a simple mean (i.e., total count / number of replicates) then I round to the nearest upper integer. Note that this rounding method gives more representation of rarer taxa. For example, say we have a sample with three replicates and caught species X at 0, 0, and 1 frequency. We get an average of 0.33 which results in an abundance of 1 after rounding up. In another scenario let’s say we catch species Y in the same sample at 20, 22, and 400 frequency. We have an average of 147.3 resulting in an abundance of 148 after rounding up. This is our first instance of data standardization, but we may want to further standardize and/or transform abundance data depending on EDA.

# Create a tibble for avg sp abundance per visit
abun = catch.2 %>%
  select(VisitID, EventID, Sp_ScientificName, Count) %>%
  summarise(Abundance = (sum(Count) / n_distinct(EventID)) %>% ceiling(), .by = c(VisitID, Sp_ScientificName))
skimr::skim(select(abun, Abundance))
Data summary
Name select(abun, Abundance)
Number of rows 13031
Number of columns 1
_______________________
Column type frequency:
numeric 1
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
Abundance 0 1 76.21 833.45 1 1 3 10 45557 ▇▁▁▁▁

3.2.3 Size information

# Create a tibble for containing length data per species and visit
size = select(catch.2, VisitID, EventID, Sp_ScientificName, Length)

3.3 Diversity

3.3.1 Choosing indices

# Create a tibble of diversity indices per sample
diversity = abun %>%
  group_by(VisitID) %>%
  summarise(S = specnumber(Sp_ScientificName), # Richness
            H = diversity(Abundance, index = "shannon"), # Shannon
            # q1 = exp(H), # exp(Shannon)
            D = diversity(Abundance, index = "simpson"), # Simpson
            # q2 = diversity(Abundance, index = "invsimpson"), # Inverse-Simpson
            J = diversity(Abundance, index = "shannon") / log(S)) # Pielou's evenness

3.3.2 Plot diversity across variables

# Function to plot diversity indices
plot_diversity = function(x) {
  dat = visits %>%
    select(VisitID, !!sym(x)) %>%
    left_join(diversity, by = "VisitID")
  plot_indices = function(dat) {
    plot_list = list()
    D.indices = names(dat)[3:6]
    for (i in 1:length(D.indices)) {
      pluck(plot_list, D.indices[i]) = ggplot(dat) +
                                        aes(x = !!sym(x), y = !!sym(D.indices[i])) +
                                        geom_jitter(alpha = 0.5)
    }
    out = ggarrange(plotlist = plot_list,
                    ncol = 2, nrow = 2,
                    common.legend = TRUE)
    return(out)
  }
  plot_indices(dat) %>% return()
}

# Define which variables to plot diversity against and save as a vector 
vars = c("Replicates", "MeshSize", "Lon", "Year", "Month")

# For each defined variable, arrange plots of diversity
map(vars, suppressMessages(plot_diversity))
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

## 
## [[5]]

3.3.3 Differences in richness

# Visualize richness by replicates
left_join(visits, diversity, by = "VisitID") %>%
  boxplot(S ~ Replicates, data = .)

# remove replicates = 9, 10, 12 bc of single obs
tmp = left_join(visits, diversity, by = "VisitID") %>%
  mutate(Replicates = as.numeric(Replicates)) %>%
  filter(Replicates < 9)

# analysis of variance
aov.S.reps = aov(S ~ as.factor(Replicates), data = tmp)
summary(aov.S.reps)
##                         Df Sum Sq Mean Sq F value Pr(>F)    
## as.factor(Replicates)    7  14067  2009.5   80.91 <2e-16 ***
## Residuals             1469  36485    24.8                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# pairwise test
TukeyHSD(aov.S.reps) %>% broom::tidy() %>% select(-term) %>% knitr::kable(digits = 3)
contrast null.value estimate conf.low conf.high adj.p.value
2-1 0 3.133 2.184 4.081 0.000
3-1 0 7.451 6.241 8.661 0.000
4-1 0 6.231 4.732 7.729 0.000
5-1 0 8.400 5.474 11.325 0.000
6-1 0 9.442 7.079 11.805 0.000
7-1 0 4.995 0.584 9.406 0.014
8-1 0 8.434 4.908 11.959 0.000
3-2 0 4.318 3.056 5.581 0.000
4-2 0 3.098 1.557 4.639 0.000
5-2 0 5.267 2.320 8.214 0.000
6-2 0 6.309 3.919 8.700 0.000
7-2 0 1.862 -2.563 6.287 0.907
8-2 0 5.301 1.757 8.844 0.000
4-3 0 -1.220 -2.935 0.494 0.377
5-3 0 0.949 -2.093 3.990 0.981
6-3 0 1.991 -0.515 4.497 0.236
7-3 0 -2.456 -6.945 2.033 0.713
8-3 0 0.983 -2.640 4.605 0.992
5-4 0 2.169 -0.998 5.336 0.429
6-4 0 3.211 0.554 5.868 0.006
7-4 0 -1.236 -5.811 3.339 0.992
8-4 0 2.203 -1.526 5.932 0.625
6-5 0 1.042 -2.615 4.699 0.989
7-5 0 -3.405 -8.624 1.814 0.496
8-5 0 0.034 -4.462 4.530 1.000
7-6 0 -4.447 -9.373 0.479 0.112
8-6 0 -1.008 -5.161 3.144 0.996
8-7 0 3.439 -2.139 9.016 0.571
# residuals
residuals = residuals(aov.S.reps)
plot(residuals)

par(mfrow = c(2, 2))
plot(aov.S.reps)

par(mfrow = c(1, 1))
# check for homogeneity
shapiro.test(residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals
## W = 0.95897, p-value < 2.2e-16
# result: violation of homogeneity

# kruskal-wallis test
kruskal.test(S ~ Replicates, data = tmp)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  S by Replicates
## Kruskal-Wallis chi-squared = 422.05, df = 7, p-value < 2.2e-16
# one way t-test not assuming equal variances
oneway.test(S ~ Replicates, data = tmp)
## 
##  One-way analysis of means (not assuming equal variances)
## 
## data:  S and Replicates
## F = 82.534, num df = 7.000, denom df = 97.828, p-value < 2.2e-16
# pairwise test
results = pairwise.t.test(tmp$S, tmp$Replicates,
                          p.adjust.method = "BH",
                          pool.sd = FALSE)
results
## 
##  Pairwise comparisons using t tests with non-pooled SD 
## 
## data:  tmp$S and tmp$Replicates 
## 
##   1       2       3       4       5       6       7      
## 2 < 2e-16 -       -       -       -       -       -      
## 3 < 2e-16 < 2e-16 -       -       -       -       -      
## 4 < 2e-16 2.9e-06 0.11531 -       -       -       -      
## 5 3.6e-08 7.5e-05 0.45956 0.11531 -       -       -      
## 6 < 2e-16 1.7e-11 0.02676 0.00083 0.45956 -       -      
## 7 0.01418 0.30978 0.18341 0.46741 0.11531 0.02886 -      
## 8 1.3e-06 0.00035 0.45956 0.11742 0.98221 0.46741 0.11531
## 
## P value adjustment method: BH
# plot t.test results
ggplot(tmp) +
  aes(x = Replicates, y = S, group = Replicates) +
  geom_boxplot() +
  geom_signif(test = "t.test",
              comparisons = list(c(1, 2),
                                 c(2, 3),
                                 c(2, 4),
                                 c(3, 4),
                                 c(3, 5)),
              y_position = c(33, 36, 39, 43, 46),
              map_signif_level = TRUE)

3.4 Species EDA plots

Walleye Pollock

Starry Flounder

Great Sculpin

Pacific Herring

Coho Salmon

Dolly Varden

3.5 MV Ordinations

3.5.1 Create catch matrix based on average abundances

# Create a data.frame in sample x species format (e.g., vegan)
abun.mat = abun %>%
  pivot_wider(names_from = Sp_ScientificName,
              values_from = Abundance,
              values_fill = 0) %>%
  column_to_rownames(var = "VisitID")

3.5.2 Standardize catch

# presence/absence
pa = decostand(abun.mat, method = "pa")

# 4th root
rt4 = mutate(abun.mat, across(everything(), ~ .x^(1/4)))

# robust CLR
rclr = decostand(abun.mat, method = "rclr")

3.5.3 Calculate distances

# Jaccard distances on P/A data
jac = vegdist(as.matrix(pa), method = "jaccard")

# Bray-Curtis distance on 4th rt transformed data
bc = vegdist(as.matrix(rt4), method = "bray")

# Euclidean distance on RCLR transformed data, i.e., robust aitchison distance
rait = vegdist(as.matrix(rclr), method = "euclidean")

3.5.4 Ordinations

nmds.jac = metaMDS(jac)
plot(nmds.jac, type = "t")

nmds.bc = metaMDS(bc)
plot(nmds.bc, type = "t")

## plot using rda() abd biplot()
# pca.rclr = rda(as.matrix(rclr))
# biplot(pca.rclr, display = c("sites", "species"), type = c("text", "points"))

mds.rclr = metaMDS(rait)
plot(mds.rclr, type = "t")

3.5.5 Look at the outlier sample

filter(visits, VisitID == "846_2015-08-15") %>%
  left_join(catch.2, by = "VisitID") %>%
  glimpse()
## Rows: 1
## Columns: 19
## $ VisitID            <chr> "846_2015-08-15"
## $ Replicates         <ord> 1
## $ Date               <date> 2015-08-15
## $ Lat                <dbl> 71.23332
## $ Lon                <dbl> -155.7281
## $ MeshSize           <ord> 3.2
## $ Cluster            <fct> 101
## $ Region             <fct> Chukchi/Beaufort
## $ Year               <dbl> 2015
## $ Month              <fct> 8
## $ Week               <ord> 33
## $ Day                <dbl> 227
## $ EventID            <dbl> 5396
## $ Fam_ScientificName <chr> "Coregoninae"
## $ Gen_ScientificName <chr> "Coregonus"
## $ Sp_ScientificName  <chr> "Coregonus laurettae"
## $ Count              <dbl> 2
## $ Length             <dbl> NA
## $ LifeStage          <chr> NA
LS0tCnRpdGxlOiAiTk9BQSBOZWFyc2hvcmUgRmlzaCBBdGxhcyBvZiBBbGFza2EiCnN1YnRpdGxlOiAiRGF0YSBXcmFuZ2xlIGFuZCBFeHBsb3JhdG9yeSBBbmFseXNlcywgUGFydCBJSSIKYXV0aG9yOiAiQ2hyaXMgR3VvIgpkYXRlOiAiTGFzdCBjb21waWxlZCBvbiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICAgIHByaW50OiBGQUxTRQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCnRoZW1lOiAiZmxhdGx5IgpiaWJsaW9ncmFwaHk6ICJgciBmaWxlLnBhdGgoaGVyZTo6aGVyZSgpLCAnZG9jLmlnbm9yZScsICduZmFhX3JlZmVyZW5jZXMuYmliJylgIgpjc2w6ICJgciBmaWxlLnBhdGgoaGVyZTo6aGVyZSgpLCAnZG9jLmlnbm9yZScsICdlY29sb2d5LmNzbCcpYCIKbGluay1jaXRhdGlvbnM6IFRSVUUKLS0tCgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UpCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UpCmtuaXRyOjpvcHRzX2NodW5rJHNldChzaXplID0gInNjcmlwdHNpemUiKQpgYGAKCkJ1aWx0IHdpdGggUiB2ZXJzaW9uIGByIGdldFJ2ZXJzaW9uKClgLgoKIyBJbnRyb2R1Y3Rpb24KClRoZSBwdXJwb3NlIG9mIHRoaXMgZG9jdW1lbnQgaXMgdG8gbWFrZSBvcGVuIGFuZCBzaGFyZS1hYmxlIHRoZSByZXNlYXJjaCBtZXRob2RzIHVzZWQgZm9yIG15IGRpc3NlcnRhdGlvbiBvbiBuZWFyc2hvcmUgZmlzaCBjb21tdW5pdGllcyBpbiBBbGFza2Egd29ya2luZyB0b3dhcmRzIGEgUGhEIGluIG1hcmluZSBiaW9sb2d5IGF0IHRoZSBVbml2ZXJzaXR5IG9mIEFsYXNrYSBGYWlyYmFua3MuIEhlcmUsIEkgY292ZXIgc2Vjb25kLXN0YWdlIHN0ZXBzIG9mIHRoZSBkYXRhIHByZXBhcmF0aW9uIGZvciBteSBzZWNvbmQgYW5kIHRoaXJkIGNoYXB0ZXJzIGNvbmNlcm5pbmcgc3BhdGlhbCBhbmQgdGVtcG9yYWwgZGlzdHJpYnV0aW9ucyBvZiBuZWFyc2hvcmUgZmlzaGVzIGFjcm9zcyB0aGUgc3RhdGUuIFRoaXMgYW5kIG90aGVyIGZpbGVzIGNhbiBiZSBhY2Nlc3NlZCB2aWEgdGhlIEthY2hlbWFrIEJheSBOYXRpb25hbCBFc3R1YXJpbmUgUmVzZWFyY2ggUmVzZXJ2ZSdzIFtnaXRodWIgcmVwb10oaHR0cHM6Ly9naXRodWIuY29tL2tibmVyci9uZWFyc2hvcmUtZmlzaCkuCgpJbiB0aGlzIGRvY3VtZW50IEkgc2hhcmUgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNlcyBjb25kdWN0ZWQgb24gdGhlIE5PQUEgTmVhcnNob3JlIEZpc2ggQXRsYXMgKE5GQSkgZGF0YWJhc2UuIFRoZSBORkEgZGF0YWJhc2UgY2FuIGJlIGZvdW5kIGhlcmUsIDxodHRwczovL2FsYXNrYWZpc2hlcmllcy5ub2FhLmdvdi9tYXBwaW5nL3N6Lz4uIE5hbWVseSwgdGhpcyBkb2N1bWVudCBjb250YWlucyB0aGUgc3RlcHMgdGFrZW4gYWZ0ZXIgY2xlYW5pbmcvd3JhbmdsaW5nIHJhdyBkYXRhLiBJbiBwYXJ0aWN1bGFyIEkgcHJvZHVjZSB2YXJpb3VzIHZpc3VhbGl6YXRpb25zIG9mIHRoZSBkYXRhIGluIHNwYWNlIGFuZCB0aW1lLiBQYXJ0IEkgb2YgdGhlc2UgZGF0YSBwcmVwYXJhdGlvbiBzdGVwcyBjYW4gYmUgYWNjZXNzZWQgYXQgPGh0dHBzOi8vcnB1YnMuY29tL2NoZ3VvMS8xMTg4NjE0PiwgYW5kIHRoZSByZXN1bHRpbmcgZGF0YSBvYmplY3RzIGFyZSBsb2FkZWQgYmVsb3cgKGZpbGUgIm5mYWFfMS5yZGEiKS4KCiMjIFNldCB1cAoKTG9hZCByZXF1aXJlZCBwYWNrYWdlcywgZGVmaW5lIGRpcmVjdG9yeSwgc2V0IG9wdGlvbnMsIHNvdXJjZS9sb2FkIGZpbGVzOgoKYGBge3IgcmVzdWx0cyA9ICdoaWRlJ30KIyBQYWNrYWdlcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh2ZWdhbikKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShnZ3B1YnIpCgojIERpcmVjdG9yeQp3ZCA9IGhlcmUoKQpkaXJzID0gd2QgJT4lIGxpc3QuZmlsZXMoKSAlPiUgc3RyX3N1YnNldChwYXR0ZXJuID0gIl5SRUFETUV8XkxJQ0VOU0V8Lm1kJHwuUnByb2okIiwgbmVnYXRlID0gVFJVRSkKZm9yIChpIGluIHNlcV9hbG9uZyhkaXJzKSkgewogIG5hbWUgPSBzdHJfcmVwbGFjZV9hbGwoZGlyc1tpXSwgIl4iLCAiZGlyLiIpCiAgcGF0aCA9IHN0cl9yZXBsYWNlX2FsbChkaXJzW2ldLCAiXiIsIHN0cl9jKHdkLCAiLyIpKQogIGFzc2lnbihuYW1lLCBwYXRoKQogIHJtKG5hbWUsIHBhdGgsIGkpCn0KCiMgT3B0aW9ucwoKIyBTb3VyY2UvTG9hZApsb2FkKGZpbGUucGF0aChkaXIuZGF0YSwgIm5mYWFfMS5yZGEiKSkgIyB3cmFuZ2xlZCBkYXRhCmBgYAoKIyMgQmFja2dyb3VuZCBhbmQgb2JqZWN0aXZlcwoKQmFzZWQgb24gbXkgb3duIHJlc2VhcmNoIGFuZCByZWxhdGVkIGxpdGVyYXR1cmUsIEkgY2FuIGJyb2FkbHkgaW50ZXJwcmV0IHRoZXNlIGJlYWNoIHNlaW5lIGRhdGEgaW4gYSBzcGF0aW90ZW1wb3JhbCBjb250ZXh0LiBEZXBlbmRpbmcgb24gd2hlbiAodGltZSBvZiB5ZWFyKSBhbmQgd2hlcmUgKGxvY2F0aW9uIGFuZCBoYWJpdGF0KSwgSSBoYXZlIGEgZ2VuZXJhbCBzdHJ1Y3R1cmUgaW4gbWluZCBvZiB0aGUgZGl2ZXJzaXR5IG9mIHRoZSBjb21tdW5pdHkuIERlcGVuZGluZyBvbiB3aG8ncyB0aGVyZSwgSSBoYXZlIGEgcm91Z2ggZ3Vlc3Mgb2YgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBlYWNoIGNvbW11bml0eSBtZW1iZXIgKGF0IGxlYXN0IGZvciB0aGUgbW9yZSBjb21tb25seSBjYXVnaHQgb25lcykuIE15IGhvcGUgd2l0aCB3b3JraW5nIHdpdGggdGhlIE5GQSBkYXRhIGlzIHRoYXQgdGhpcyBicm9hZCB1bmRlcnN0YW5kaW5nIGNhbiBiZSBmb3JtYWxseSB0ZXN0ZWQgd2l0aCBpbmZlcmVuY2UgYW5kIHN0YXRpc3RpY3MsIGFuZCB0aGF0IG1vcmUgaW5mb3JtYXRpdmUgcmVzZWFyY2ggcXVlc3Rpb25zIGNhbiBiZSBhbnN3ZXJlZC4KCkZpbmRpbmdzIGZyb20gb3RoZXIgbmVhcnNob3JlIGZpc2ggcmVzZWFyY2hlcnMgbGFyZ2VseSBhZ3JlZSB0aGF0IHNlYXNvbmFsaXR5IChvciBzb21lIHJlbGF0ZWQgZW52aXJvbm1lbnRhbCBjb25kaXRpb24pIGlzIGEgc3Ryb25nIHByZWRpY3RvciBvZiBjb21tdW5pdHkgb3Igc3BlY2llcyBwcmVzZW5jZS4gSW50ZXJhbm51YWwgZGlmZmVyZW5jZXMgY2FuIGV4aGliaXQgd2lkZSB2YXJpYWJpbGl0eSBhbmQgc2hvdWxkIGJlIGFjY291bnRlZCBmb3Igd2hlbmV2ZXIgcG9zc2libGUuIEFuZCBhdCBsYXJnZXIgdGltZS1zY2FsZXMgKGUuZy4sIGRlY2FkYWwpLCBjb21tdW5pdGllcyBleGhpYml0IGNoYW5nZXMgd2hpY2ggbWF5IHJlbGF0ZSB0byByZWdpbWUgc2hpZnRzIG9jY3VycmluZyBtb3JlIGJyb2FkbHkgdGhhbiB0aGUgbmVhcnNob3JlLgoKU3BhdGlhbGx5LCBsYXJnZS1zY2FsZSAocmVnaW9uYWwpIGVmZmVjdHMgYXBwZWFyIHRvIGJlIGFzIG9yIG1vcmUgaW1wb3J0YW50IHRoYW4gc3ViLXJlZ2lvbmFsIG9yIGxvY2FsLXNjYWxlIGVmZmVjdHMuIEhvd2V2ZXIsIG1hbnkgc3R1ZGllcyBhbHNvIGZpbmQgc2lnbmlmaWNhbnQgcmVsYXRpb25zaGlwcyBpbiBjb21tdW5pdHkgcmVzcG9uc2UgYXQgdGhlc2Ugc21hbGxlciBzY2FsZXMuIExpa2VseSwgdGhlIG1vc3QgYXBwcm9wcmlhdGUgc3BhdGlhbCBjb25zaWRlcmF0aW9uIGRlcGVuZHMgb24gdGhlIHF1ZXN0aW9uIGJlaW5nIGFza2VkLiBTbyBtYXliZSBhIG1vcmUgYXBwcm9wcmlhdGUgcXVlc3Rpb24gdG8gYXNrIG9mIHRoZSBORkEgZGF0YSBpcyBpZiB0aGVyZSBhbnkgc2lnbmlmaWNhbnQgc3BhdGlhbCBzY2FsZXMgZGlzY2VybmlibGUgaW4gdGhlIGRhdGEsIGFuZCBhbHNvIGhvdyBzaG91bGQgd2UgYWRkcmVzcyB0aG9zZSBzY2FsZXMgaW4gZnV0dXJlIHJlc2VhcmNoLCBzdWNoIGFzIHN0dWRpZXMgb24gc3Vic2V0cyBvZiB0aGUgdGF4YSBvciBoYWJpdGF0IG1hbmFnZW1lbnQgY29uc2lkZXJhdGlvbnMuCgpJJ2xsIHN0YXJ0IGJ5IGV4cGxvcmluZyB0aGUgc3RydWN0dXJlIG9mIG91ciAndmlzaXRzJyBkYXRhZnJhbWUsIGFuZCB0aGVuIEknbGwgbW92ZSBvbiB0byB2aXN1YWxpemluZyB0aGUgaW5mb3JtYXRpb24gZGVyaXZlZCBmcm9tIG91dCAnY2F0Y2gnIGRhdGFmcmFtZS4KCiMgRXhwbG9yaW5nIHZpc2l0IGRhdGEKCiMjIFN1bW1hcnkgb2YgdmlzaXRzCgpSZW1lbWJlciB0aGF0IGluIHRoZSBkYXRhIHdyYW5nbGluZyBzdGFnZSwgd2UgY3JlYXRlZCBhIG5ldyBzYW1wbGUgaWRlbnRpZmllciBiYXNlZCBvbiBzaXRlIGFuZCBkYXRlIHdoaWNoIHdlIGNhbGxlZCBWaXNpdElELiBMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdmFyaWFibGVzIGFzc29jaWF0ZWQgd2l0aCBlYWNoIFZpc2l0SUQ6CgpgYGB7cn0KZ2xpbXBzZSh2aXNpdHMpCmBgYAoKRHVyaW5nIHRoZSB3cmFuZ2xpbmcgc3RhZ2UsIEkgZGVjaWRlZCB0aGF0IFJlcGxpY2F0ZXMgYW5kIE1lc2hTaXplIHNob3VsZCBiZSB0aGUgbWFpbiBjb3ZhcmlhdGVzIHRoYXQgbmVlZGVkIGNvbnNpZGVyYXRpb24uIEF0IHRoaXMgcG9pbnQgdGhleSBhcmUgY2xhc3NlZCBhcyBpbnRlZ2Vycy9udW1iZXJzLCBidXQgd2Ugd2lsbCBwcm9iYWJseSB3YW50IHRoZW0gdG8gYmUgZmFjdG9ycyBpbnN0ZWFkLiBDbHVzdGVyIGlzIGEgYnlwcm9kdWN0IG9mIGNsdXN0ZXJpbmcgc29tZSBzaXRlcyB0b2dldGhlciwgc28gaXQgbWF5IG5vdCBiZSBuZWVkZWQgaWYgd2UncmUgdXNpbmcgTGF0L0xvbiBhcyBvdXIgcHJpbWFyeSBleHBsYW5hdG9yeSB2YXJpYWJsZS4gU3RpbGwsIGl0IGNvdWxkIGJlIGEgdXNlZnVsIGdyb3VwaW5nIGZhY3RvciBsYXRlciBvbi4gRGF0ZSB3aWxsIGxpa2VseSBiZSBtdXRhdGVkIGludG8gbXVsdGlwbGUgYWRkaXRpb25hbCBwZXJpb2RzIChkYXkgb2YgeWVhciwgbW9udGgsIHllYXIpIHRvIHNlZSBpZiBhbnkgb2YgdGhvc2UgZmFjdG9ycyBhcmUgdXNlZnVsIGluIGV4cGxhaW5pbmcgZmlzaCBkYXRhLiBXZSdsbCBhZGRyZXNzIGVkaXRzIHRvIHRoZXNlIHZhcmlhYmxlcyBhcyB0aGV5IGNvbWUgdXAgaW4gb3VyIGV4cGxvcmF0aW9uLgoKIyMgU3BhdGlhbCBkaXN0cmlidXRpb24KCmBgYHtyfQpsZWFmbGV0KHZpc2l0cykgJT4lIAogIGFkZFRpbGVzKG9wdGlvbnMgPSB0aWxlT3B0aW9ucyhtaW5ab29tID0gMy41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6SW5kZXggPSAwLjUpKSAlPiUKICBzZXRWaWV3KGxhdCA9IDY1LCBsbmcgPSAtMTUyLCB6b29tID0gMy41KSAlPiUKICBhZGRTaW1wbGVHcmF0aWN1bGUoaW50ZXJ2YWwgPSA1KSAlPiUgIAogIGFkZENpcmNsZU1hcmtlcnMobG5nID0gfkxvbiwgbGF0ID0gfkxhdCwKICAgICAgICAgICAgICAgICAgIHN0cm9rZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+VmlzaXRJRCwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSkKYGBgCgpJbiB0aGUgbWFwIGFib3ZlIHdlIGNhbiB2aWV3IGFsbCBvZiBvdXIgc2FtcGxlcyBmcm9tIGFjcm9zcyBBbGFza2EuIExlYWZsZXQgb3B0aW9ucyBhcmUgbmljZSBiZWNhdXNlIHlvdSBjYW4gb3B0aW9uYWxseSBncm91cCBzYW1wbGVzIG9uIHRoZSBtYXAgYW5kIHNob3cgYSBib3VuZGFyeSBwb2x5Z29uIG9mIHRoZSBhcmVhIHRoZXkgY292ZXIgd2hlbiB5b3UgaG92ZXIgb3ZlciB0aGVpciBpY29uLiBBdCB0aGUgbWluaW11bSB6b29tIGxldmVsICgzLjUpLCB3ZSBzZWUgdGhlIGxhcmdlc3QgZ3JvdXAgc3Bhbm5pbmcgbmVhcmx5IGFsbCBvZiBTb3V0aGVhc3QgQWxhc2thLCBmb2xsb3dlZCBieSBhIGdyb3VwIGluIFNvdXRoY2VudHJhbCB0aGF0IGNvdmVycyBQcmluY2UgV2lsbGlhbSBTb3VuZCwgQ29vayBJbmxldCwgYW5kIHRoZSBub3J0aGVybiBoYWxmIG9mIEtvZGlhayBJc2xhbmQuIFRoZSB0aGlyZCBsYXJnZXN0IGdyb3VwIGZvcm1zIGEgbXVjaCBzbWFsbGVyIHBvbHlnb24gYXJlYSBhcm91bmQgVXRxaWFndmlrLiBGcm9tIHRoZXJlLCB3ZSBzZWUgZXZlbiBzbWFsbGVyIGdyb3VwcyBmcm9tIHRoZSBFYXN0ZXJuIEJlYXVmb3J0IFNlYSBhcm91bmQgS2FrdG92aWssIHRoZSBCZXJpbmcgU3RyYWl0IGFuZCBTb3V0aGVybiBDaHVrY2hpIFNlYSBuZWFyIEtvdHplYnVlLCBhbmQgQnJpc3RvbCBCYXkuIFRoZXJlIGFyZSBhbHNvIHR3byBncm91cHMgZnJvbSB0aGUgQWxhc2thIFBlbmluc3VsYSBhbmQgQWxldXRpYW4gSXNsYW5kcywgb25lIGZvY3VzZWQgYXJvdW5kIEFkYWsgYW5kIGFub3RoZXIgc3Bhbm5pbmcgZnJvbSBTYW5kIFBvaW50IHRvIFVuYWxhc2thLiBXZSBjYW4gc2VlIGhvdyBzdWJzZXRzIG9mIHRoZSBzYW1wbGVzIGNoYW5nZSBieSB6b29taW5nIGluLiBXaGVuIHRoZXJlIGFyZSBzaW5nbGUgc2FtcGxlcyBpbiB2aWV3LCBob3ZlcmluZyBvdmVyIHRob3NlIHdpbGwgdGVsbCB1cyBpdHMgVmlzaXRJRCBuYW1lLgoKT2J2aW91c2x5LCB0aGlzIHZpc3VhbGl6YXRpb24gb2YgdGhlIGRhdGEgaXMgbm90IHBlcmZlY3QgYW5kIHByZXR0eSByb3VnaC0gbm90ZSB0aGF0IHRoZSBncm91cHMgYXJlIGZvcm1lZCBieSB0aGUgb3ZlcmxhcCBvZiBzYW1wbGVzIGJhc2VkIG9uIHBpeGVsIHJhZGl1cyAoMTApLiBGb3IgZXhhbXBsZSwgdGhlIHBvbHlnb24gb2Ygc2FtcGxlcyBmcm9tIEJyaXN0b2wgQmF5IGF0IHRoZSBtaW5pbXVtIHpvb20gbGV2ZWwgYWN0dWFsbHkgY3Jvc3NlcyB0aGUgQWxhc2thIFBlbmluc3VsYSB0byBpbmNsdWRlIGEgc2FtcGxlIGZyb20gQWdoaXl1ayBJc2xhbmQuIEFsdGhvdWdoLCB0aGUgbWFwIGlzIHVzZWZ1bCBpbiBnYWluaW5nIGEgZ2VuZXJhbCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBleGlzdGluZyBjbHVzdGVycyBvZiBzYW1wbGVzIHdpdGhpbiB0aGUgTkZBIGRhdGFiYXNlLgoKIyMgUmVnaW9ucwoKV2UgbWF5IHdhbnQgdG8gZGVmaW5lIGEgc3BhdGlhbCBmYWN0b3IgYmFzZWQgb24gdGhlc2Ugcm91Z2ggZ3JvdXBpbmdzIGFzIGEgc3RhcnRpbmcgcGxhY2UgdG8gc2VlIGlmIHRoZSBzbWFsbGVyLCBtb3JlIGlzb2xhdGVkIGdyb3VwcyBzaG91bGQgYmUgbHVtcGVkIHdpdGggb3RoZXIgZ3JvdXBzIG9yIG5vdC4gQWN0dWFsbHksIHRoZSBORkEgYWxyZWFkeSBoYXMgYSBSZWdpb24gY2xhc3NpZmllciBwZXIgc2l0ZSwgYnV0IHRoZSByZWFzb24gSSBkbyBub3Qgd2FudCB0byB1c2UgaXQgaXMgYmVjYXVzZSB0aGV5IGxpbmtlZCBSZWdpb24gdG8gU2l0ZUlELiBXaGVuIHdlIGNyZWF0ZWQgb3VyIG5ldyBWaXNpdElELCBzb21lIHNhbXBsZXMgbm93IGNvbnRhaW5lZCB0d28gUmVnaW9uIGxhYmVscy0gdGhlc2Ugd2VyZSBtb3N0bHkgY2FzZXMgZnJvbSBhcm91bmQgVXRxaWFndmlrIHdoZXJlIHNvbWUgd2VyZSBsYWJlbGxlZCBhcyBDaHVja2NoaSBhbmQgb3RoZXJzIGFzIEJlYXVmb3J0IGJ1dCBhY3R1YWxseSBvY2N1cnJlZCBvbiB0aGUgc2FtZSBkYXkgYW5kIHdpdGhpbiBhIHZlcnkgc2hvcnQgZGlzdGFuY2Ugb2YgZWFjaCBvdGhlci4KCkluc3RlYWQgb2YgdXNpbmcgdGhlIHRoZSBnaXZlbiByZWdpb25hbCBjbGFzc2VzLCBsZXQncyBqdXN0IG1ha2Ugb3VyIG93biB2YXJpYWJsZSBjYWxsZWQgJ1JlZ2lvbicgYW5kIGFkZCBpdCB0byB0aGUgb3VyIHZpc2l0cyBkZjoKCmBgYHtyfQojIFN0YXJ0IHdpdGggZXZlbnRzIHNvIHRoYXQgd2UgY2FuIG1ha2UgdXNlIG9mIExvY2F0aW9uIGluZm8gZm9yIHVuaXF1ZSBjYXNlcywKcmVnaW9ucyA9IGV2ZW50cyAlPiUKICBzZWxlY3QoRXZlbnRJRCwgVmlzaXRJRCwgTGF0LCBMb24sIExvY2F0aW9uKSAlPiUKICBtdXRhdGUoUmVnaW9uID0gY2FzZV93aGVuKExhdCA+IDY5ICYgTGF0IDwgODAgJiBMb24gPiAtMTUwICYgTG9uIDwgLTE0MCB+ICJCZWF1Zm9ydCBFYXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIExhdCA+IDY5ICYgTGF0IDwgODAgJiBMb24gPiAtMTYwICYgTG9uIDwgLTE1MCB+ICJDaHVrY2hpL0JlYXVmb3J0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIExhdCA+IDY1ICYgTGF0IDwgNjkgJiBMb24gPiAtMTcwICYgTG9uIDwgLTE2MCB+ICJDaHVrY2hpIFNvdXRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIExhdCA+IDU3ICYgTGF0IDwgNjAgJiBMb24gPiAtMTY1ICYgTG9uIDwgLTE1NSB+ICJCcmlzdG9sIEJheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYXQgPiA1MCAmIExhdCA8IDU1ICYgTG9uID4gLTE4MCAmIExvbiA8IC0xNzUgfiAiQWxldXRpYW5zIEFkYWsiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF0ID4gNTAgJiBMYXQgPCA1NSAmIExvbiA+IC0xNzAgJiBMb24gPCAtMTY1IH4gIkFsZXV0aWFucyBVbmFsYXNrYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYXQgPiA1NSAmIExhdCA8IDY1ICYgTG9uID4gLTE1NSAmIExvbiA8IC0xNDUgfiAiR09BIFNvdXRoY2VudHJhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYXQgPiA1MyAmIExhdCA8IDYxICYgTG9uID4gLTE0OCAmIExvbiA8IC0xMzAgfiAiR09BIFNvdXRoZWFzdCIpKQoKIyBDaGVjayB3aGljaCBzYW1wbGVzIHdlIG1pc3NlZCwKZmlsdGVyKHJlZ2lvbnMsIGlzLm5hKFJlZ2lvbikpCgojIExldCdzIGFkZHJlc3MgdGhvc2UgdXNpbmcgTG9jYXRpb24sCnJlZ2lvbnMgPSBtdXRhdGUocmVnaW9ucywKICAgICAgIFJlZ2lvbiA9IGNhc2Vfd2hlbighaXMubmEoUmVnaW9uKSB+IFJlZ2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShSZWdpb24pICYgc3RyX2RldGVjdChMb2NhdGlvbiwgIll1bmFza2EiKSB+ICJBbGV1dGlhbnMgWXVuYXNrYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoUmVnaW9uKSAmIHN0cl9kZXRlY3QoTG9jYXRpb24sICJBZ2hpeXVrIikgfiAiQWxldXRpYW5zIEFnaGl5dWsiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKFJlZ2lvbikgJiBzdHJfZGV0ZWN0KExvY2F0aW9uLCAiU2h1bWFnaW4iKSB+ICJBbGV1dGlhbnMgU2h1bWFnaW4iKSkKCiMgQ2hlY2sgYWdhaW4gKHNob3VsZCBiZSAwKSwKZmlsdGVyKHJlZ2lvbnMsIGlzLm5hKFJlZ2lvbikpICU+JSBucm93KCkKYGBgCgpOb3cgbGV0J3MgYWRkIFJlZ2lvbiBhcyBhIGZhY3RvciB0byBvdXIgdmlzaXRzIGRmLCBhbmQgc2hvdyBpdCBvbiBhIG1hcC4gU2luY2Ugd2UncmUgbWFuaXB1bGF0aW5nIG91ciBkYXRhIG9iamVjdHMgYWdhaW4sIGxldCdzIGFsc28gcmVuYW1lIHZpc2l0cyBzbyB0aGF0IHdlIGNhbiBrZWVwIHRyYWNrIG9mIG91ciBjaGFuZ2VzLgoKYGBge3J9CiMgQ2FsbCBvdXIgd3JhbmdsZWQgZGYgdmVyc2lvbiB2aXNpdHMuMCBhbmQgcmVtb3ZlIHRoZSBub24tdmVyc2lvbiAndmlzaXRzJyBpZiBpdCdzIHRoZXJlLAppZiAoInZpc2l0cyIgJWluJSBscygpKSBhc3NpZ24oInZpc2l0cy4wIiwgdmlzaXRzKQppZiAoInZpc2l0cyIgJWluJSBscygpKSBybSh2aXNpdHMpCgojIE1ha2UgUmVnaW9uIGEgZmFjdG9yIGFuZCBqb2luIGJ5IFZpc2l0SUQsCnZpc2l0cy4xID0gcmVnaW9ucyAlPiUKICBzZWxlY3QoVmlzaXRJRCwgUmVnaW9uKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIG11dGF0ZShSZWdpb24gPSBhcy5mYWN0b3IoUmVnaW9uKSkgJT4lCiAgbGVmdF9qb2luKHZpc2l0cy4wLCAuLCBieSA9ICJWaXNpdElEIikKCiMgRnVuY3Rpb24gZm9yIHJlZ2lvbmFsIHBhbGV0dGUKcGFsZXR0ZS5yZWdpb24gPSBjb2xvckZhY3RvcihwYWxldHRlID0gYnJld2VyLnBhbChuID0gdmlzaXRzLjEkUmVnaW9uICU+JSBuX2Rpc3RpbmN0KCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICdTcGVjdHJhbCcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbiA9IGZhY3Rvcih2aXNpdHMuMSRSZWdpb24pKQoKIyBNYXAKbGVhZmxldCh2aXNpdHMuMSkgJT4lIAogIGFkZFRpbGVzKCkgJT4lCiAgYWRkQ2lyY2xlTWFya2VycyhsbmcgPSB+TG9uLCBsYXQgPSB+TGF0LAogICAgICAgICAgICAgICAgICAgY29sb3IgPSB+cGFsZXR0ZS5yZWdpb24oUmVnaW9uKSwKICAgICAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IH5wYWxldHRlLnJlZ2lvbihSZWdpb24pLAogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+cGFzdGUoUmVnaW9uLCBWaXNpdElEKSwKICAgICAgICAgICAgICAgICAgIHN0cm9rZSA9IEZBTFNFKSAlPiUKICBhZGRMZWdlbmQocG9zaXRpb24gPSAidG9wcmlnaHQiLAogICAgICAgICAgICBwYWwgPSBwYWxldHRlLnJlZ2lvbiwgdmFsdWVzID0gflJlZ2lvbiwKICAgICAgICAgICAgdGl0bGUgPSAiUmVnaW9uIiwKICAgICAgICAgICAgb3BhY2l0eSA9IDAuNzUpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQojIE51bWJlciBvZiBzYW1wbGVzIHBlciBSZWdpb24Kc2VsZWN0KHZpc2l0cy4xLCBWaXNpdElELCBSZWdpb24pICU+JQogIGNvdW50KFJlZ2lvbikgJT4lCiAgZGlzdGluY3QoKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHggPSBSZWdpb24sIHkgPSBuLCBmaWxsID0gUmVnaW9uKSkgKwogIGdlb21fY29sKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgdmp1c3QgPSAtMC41KSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgdGl0bGUgPSAiTm8uIHNhbXBsZXMgcGVyIFJlZ2lvbiIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKTGlrZSB3ZSBzYXcgYmVmb3JlLCB0aGUgbWFqb3JpdHkgb2Ygb3VyIHNhbXBsZXMgYXJlIGxvY2F0ZWQgaW4gdGhlIEd1bGYgb2YgQWxhc2thIChHT0EpLCBuYW1lbHkgU291dGhlYXN0IChTRUFrKSBhbmQgU291dGhjZW50cmFsIChTQ0FLKS4gSWYgd2Ugd2VyZSB0byBsb29rIGF0IGRpZmZlcmVuY2VzIGluIGNhdGFjaCBpbiB0aGUgR09BLCBpdCdkIGJlIGNvb2wgaWYgd2UgY291bGQgaW5jbHVkZSB0aGUgQWxldXRpYW4gc2FtcGxlcyB0b28uIE9idmlvdXNseSwgd2UnbGwgd2FudCB0byBhZGRyZXNzIHRob3NlIGZldyBpbnN0YW5jZXMgZnJvbSBBZ2hpeXVrLCBTaHVtYWdpbiwgYW5kIFl1bmFza2EsIGFuZCBpZGVhbGx5IHdlIGFnZ3JlZ2F0ZSB0aGVtIGludG8gb25lIG9yIHR3byBncm91cHMuIFdlIGFsc28gc2VlIHJlbGF0aXZlbHkgc21hbGwgc2FtcGxlIHNpemVzIGZyb20gQnJpc3RvbCBCYXkgYW5kIGZyb20gRWFzdCBCZWF1Zm9ydCwgd2hpY2ggbWF5IG9yIG1heSBub3QgYmUgcHJvaGliaXRpdmUgaW4gY29uZHVjdGluZyBtZWFuaW5nZnVsIHRlc3RzLiBPbmUgb3RoZXIgY29uc2lkZXJhdGlvbiBpcyB0aGUgY291cGxlIG9mIHNhbXBsZXMgYWxvbmcgdGhlIEJlcmluZyBTdHJhaXQgY29hc3Qgd2hpY2ggYXJlIGx1bXBlZCB0b2dldGhlciB3aXRoIGEgbGFyZ2VyIGNvbmNlbnRyYXRpb24gb2Ygc2FtcGxlcyBmcm9tIFNvdXRoIENodWtjaGkuCgpTb21lIG9mIG91ciBmaXJzdCBhbmFseXNlcyBzaG91bGQgc2VlIGlmIHRoZSBtb3JlIGlzb2xhdGVkIHNhbXBsZXMgYXJlIGRpZmZlcmVudCBmcm9tIHRoZSBvdGhlciBzYW1wbGVzLiBJZiBub3QsIHRoZW4gd2UgY2FuIGFnZ3JlZ2F0ZS4gSWYgeWVzLCB0aGVuIHdlIHNob3VsZCByZXBvcnQgYW55IHNpZ25pZmljYW50IHRlc3RzLgoKIyMgVGVtcG9yYWwgZGlzdHJpYnV0aW9uCgpOZXh0IHdlJ2xsIHdhbnQgdG8gdGFrZSBhIGxvb2sgYXQgaG93IG91ciBzYW1wbGVzIGRpc3RyaWJ1dGUgdGhyb3VnaG91dCB2YXJpb3VzIHRpbWUgcGVyaW9kcy4gVGhpcyB3aWxsIGdpdmUgdXMgYSBnb29kIGlkZWEgb2YgaG93IHdlbGwgb3VyIHNhbXBsZXMgbWF5IG9yIG1heSBub3Qgb3ZlcmxhcC0gcGFydGljdWxhcmx5LCB3ZSdsbCB3YW50IHRvIHNlZSBvdmVybGFwcyBpbiB5ZWFycyBhbmQgbW9udGhzIGZvciBiZXR0ZXIgY29tcGFyaXNvbnMgb2YgdGhlIGNhdGNoIGRhdGEuCgpgYGB7cn0KIyBGaXJzdCBjcmVhdGUgYSBkZiBzcGVjaWZpY2FsbHkgY29udGFpbmluZyBhdCB0aW1lIHZhcmlhYmxlcwp0aW1lcyA9IHZpc2l0cy4xICU+JQogIHNlbGVjdChWaXNpdElELCBEYXRlKSAlPiUKICBtdXRhdGUoWWVhciA9IHllYXIoRGF0ZSksCiAgICAgICAgIE1vbnRoID0gbW9udGgoRGF0ZSwgbGFiZWwgPSBUUlVFKSwKICAgICAgICAgV2VlayA9IHdlZWsoRGF0ZSksCiAgICAgICAgIERheSA9IHlkYXkoRGF0ZSkpCgojIEZ1bmN0aW9uIHRvIGdlbmVyYXRlIGZyZXF1ZW5jeSBwbG90cyBmb3IgdGVtcG9yYWwgdmFycwpwbG90X3RpbWVzID0gZnVuY3Rpb24oeCkgewogIHRpbWVzICU+JQogICAgZmlsdGVyKFllYXIgPiAxOTgwKSAlPiUKICAgIGNvdW50KCEhc3ltKHgpKSAlPiUKICAgIGRpc3RpbmN0KCkgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHggPSAhIXN5bSh4KSwgeSA9IG4pKSArCiAgICBnZW9tX2NvbCgpICsKICAgIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLAogICAgICAgICB0aXRsZSA9IHBhc3RlKCJOby4gc2FtcGxlcyBwZXIiLCB4LCBzZXAgPSAiICIpLAogICAgICAgICBzdWJ0aXRsZSA9ICJ3L28gZGF0YSBmcm9tIDE5NzYiKSAKfQoKIyBHZW5lcmF0ZSBwbG90cwptYXAobmFtZXModGltZXMpWzM6Nl0sIHBsb3RfdGltZXMpCmBgYAoKQnkgeWVhciwgd2Ugc2VlIGEgbGFyZ2UgdmFyaWFiaWxpdHkgaW4gbnVtYmVyIG9mIHNhbXBsZXMsIGFzIHdlbGwgYXMgYSBsb25lIDE5NzYgeWVhciB3aGljaCBJIHJlY29nbml6ZSB0byBiZSBCbGFja2J1cm4ncyBkYXRhc2V0IGZyb20gTG93ZXIgQ29vayBJbmxldC4gVGhhdCAxOTc2IGlzIGFuIGludGVyZXN0aW5nIGRhdGFzZXQgdGhhdCBjb3VsZCBiZSB1c2VmdWwgZm9yIGEgbG9vayBhdCBjYXRjaGVzIG92ZXIgdGltZSBpbiB0aGF0IHNwZWNpZmljIGFyZWEsIGJ1dCBpdCdsbCBuZWVkIHRvIGJlIGV4Y2x1ZGVkIGZyb20gYW55IG90aGVyIGNvbXBhcmlzb25zLiBUaGUgbG93ZXN0IG51bWJlciBvZiBzYW1wbGVzIG9jY3VyIGluIDIwMTAsIDIwMjAsIGFuZCAyMDIxLiBXZSBtYXkgd2FudCB0byBwYXkgY2xvc2UgYXR0ZW50aW9uIHRvIHRoZXNlIHllYXJzIGluIGNhc2UgdGhleSBzaG93IHVwIGFzIG91dGxpZXJzLiBJdCBzZWVtcyB0aGF0IDE5OTYtMjAwMCBpcyBhIHBlcmlvZCBvZiBoZWF2eSBzYW1wbGluZywgZm9sbG93ZWQgYnkgdGhlIG1pZCAyMDEwcyBhbmQgc29tZXdoYXQgYWN0aXZlIHllYXIgaW4gMjAwNi4KCkJ5IG1vbnRoLCB3ZSBzZWUgYW4gb2J2aW91cyB1cHRpY2sgZHVyaW5nIHRoZSBzdW1tZXIgd2hpY2ggbWFrZXMgc2Vuc2UgZ2l2ZW4gd2ludGVyIGNvbmRpdGlvbnMgYWxvbmcgbW9zdCBvZiBBbGFza2EncyBjb2FzdCAobGlnaHQsIGljZSwgZXRjLikuIE1hcmNoIGFuZCBPY3RvYmVyIGFyZSBpbnRlcmVzdGluZyBtb250aHMgYmVjYXVzZSBvZiB0aGUgcG90ZW50aWFsIGZvciBpbXBhY3RzIG9uIGZpc2hlcyBkdXJpbmcgeWVhcnMgd2l0aCB3YXJtZXIgc2hvdWxkZXIgc2Vhc29ucy4gTm92ZW1iZXIgdGhydSBGZWJydWFyeSB3aWxsIGxpa2VseSBiZSByZW1vdmVkIGZvciBvdXIgcHVycG9zZXMuIE91ciBrZXkgbW9udGhzIGxvb2sgdG8gYmUgSnVuZSwgSnVseSBhbmQgQXVndXN0LCB3aXRoIHBvc3NpYmxlIGluY2x1c2lvbiBvZiBBcHJpbCwgTWF5LCBhbmQgU2VwdGVtYmVyLgoKSXQncyBpbnRlcmVzdGluZyBpZiB3ZSBsb29rIGF0IHRoZSBieS13ZWVrIGFuZCBieS1kYXkgZ3JhcGhzLCB3ZSBzZWUgYSBkaXAgaW4gc2FtcGxpbmcgYXJvdW5kIG1pZC1KdW5lL2Vhcmx5LUp1bHkuIE5vdCBzdXJlIHdoeSB0aGlzIGlzLSBtYXliZSByZWxhdGVkIHRvIG1vcmUgdGFyZ2V0aW5nIG9mIGp1dmVuaWxlIHNhbG1vbmlkcyBpbiBlYXJseSBKdW5lLCBvciBtYXliZSBzbyByZWR1Y2VkIGVmZm9ydCBhcm91bmQgdGhlIDR0aCBvZiBKdWx5IGhvbGlkYXkuCgojIyBZZWFyICYgTW9udGggYnkgUmVnaW9uCgpMZXQncyBub3cgc2VlIGhvdyBvdXIgc2FtcGxlcyBvdmVybGFwIGJ5IFJlZ2lvbiBhbmQgWWVhciwgYW5kIGJ5IFJlZ2lvbiBhbmQgTW9udGguIEZvciB0aGVzZSBwdXJwb3NlcywgbGV0J3MgY29tYmluZSB0aGUgQWxldXRpYW5zIGludG8gb25lIGdyb3VwIGZvciBub3csIGFuZCByZW1vdmUgdGhlIDE5NzYgZGF0YS4KCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBTYW1wbGVzIGJ5IFllYXIgYW5kIFJlZ2lvbiwKbGVmdF9qb2luKGZpbHRlcih0aW1lcywgWWVhciA+IDE5ODApLAogICAgICAgICAgc2VsZWN0KHZpc2l0cy4xLCBWaXNpdElELCBSZWdpb24pLCBieSA9ICJWaXNpdElEIikgJT4lCiAgbXV0YXRlKFJlZ2lvbiA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KFJlZ2lvbiwgIkFsZXV0aWFucyIpIH4gIkFsZXV0aWFucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChSZWdpb24sICJBbGV1dGlhbnMiKSB+IFJlZ2lvbikpICU+JQogIGdncGxvdChhZXMoeCA9IERhdGUsIHkgPSBSZWdpb24sIGNvbG9yID0gUmVnaW9uKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihzaXplID0gMC41LCBhbHBoYSA9IDAuNzUpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJ0ZXh0Iiwgdmp1c3QgPSAtMS45LCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgewogICAgICAgICAgICAgICAgIHJldHVybihjKHkgPSBtZWRpYW4oeCksIGxhYmVsID0gbGVuZ3RoKHgpKSkKICAgICAgICAgICAgICAgfSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNwZWN0cmFsIikgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIleSIsCiAgICAgICAgICAgICAgIGRhdGVfYnJlYWtzID0gIjIgeWVhcnMiKSArCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIlJlZ2lvbiIsCiAgICAgICB0aXRsZSA9ICJTYW1wbGVzIGJ5IFllYXIgYW5kIFJlZ2lvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJOby4gc2FtcGxlcyBjZW50ZXJlZCBvdmVyIG1lZGlhbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiMgU2FtcGxlcyBieSBNb250aCBhbmQgUmVnaW9uLApsZWZ0X2pvaW4oZmlsdGVyKHRpbWVzLCBZZWFyID4gMTk4MCksCiAgICAgICAgICBzZWxlY3QodmlzaXRzLjEsIFZpc2l0SUQsIFJlZ2lvbiksIGJ5ID0gIlZpc2l0SUQiKSAlPiUKICBtdXRhdGUoUmVnaW9uID0gY2FzZV93aGVuKHN0cl9kZXRlY3QoUmVnaW9uLCAiQWxldXRpYW5zIikgfiAiQWxldXRpYW5zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KFJlZ2lvbiwgIkFsZXV0aWFucyIpIH4gUmVnaW9uKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gTW9udGgsIHkgPSBSZWdpb24sIGNvbG9yID0gUmVnaW9uKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihzaXplID0gMC41LCBhbHBoYSA9IDAuNzUpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJ0ZXh0Iiwgdmp1c3QgPSAtMS45LCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgIGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgewogICAgICAgICAgICAgICAgIHJldHVybihjKHkgPSBtZWRpYW4oeCksIGxhYmVsID0gbGVuZ3RoKHgpKSkKICAgICAgICAgICAgICAgfSkrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArCiAgbGFicyh4ID0gIk1vbnRoIiwgeSA9ICJSZWdpb24iLAogICAgICAgdGl0bGUgPSAiU2FtcGxlcyBieSBNb250aCBhbmQgUmVnaW9uIiwKICAgICAgIHN1YnRpdGxlID0gIkV4Y2x1ZGluZyAxOTc2OyBuby4gc2FtcGxlcyBsYWJlbGxlZCBieSBtb250aCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpJbnRlcmVzdGluZyB0aGF0IGVhY2ggcmVnaW9uJ3Mgc2FtcGxlcyBjZW50ZXIgb24gYSBkaWZmZXJlbnQgeWVhci4gQXQgYSBnbGFuY2UsIEkgc2VlIHRoZSBtb3N0IG92ZXJsYXAgaW4gMjAwNiB3aGVyZSB0aGUgQWxldXRpYW5zIGFuZCBib3RoIEdPQSByZWdpb25zIGxvb2sgdG8gaGF2ZSBzaW1pbGFyIHNhbXBsZSBkZW5zaXRpZXMsIHBsdXMgdGhlcmUgaXMgYSBzbWF0dGVyaW5nIG9mIENodWtjaGkvQmVhdWZvcnQgc2FtcGxpbmcgdG9vLiBJbiAyMDA5LCB0aGUgQnJpc3RvbCBCYXkgc2FtcGxlcyBtYXkgYmUgY29tcGFyZWQgd2l0aCBib3RoIEdvQSByZWdpb25zIGFuZCB0aGUgQ2h1a2NoaS9CZWF1Zm9ydCwgYWx0aG91Z2ggdGhlIHNhbXBsZXMgbG9vayBtb3JlIHNwYXJzZSBhY3Jvc3MgdGhlIHJlZ2lvbnMuIEFuZCBpbiAyMDEzLCB0aGUgQ2h1a2NoaS9CZWF1Zm9ydCBoYXMgZ29vZCBvdmVybGFwIHdpdGggYm90aCBHT0EgcmVnaW9ucyBhZ2Fpbi4gSSBzZWUgbmljZSBwZXJpb2RzIG9mIGNvbXBhcmlzb24gYmV0d2VlbiBTRUFLIGFuZCBTQ0FLLCBidXQgdGhlcmUgaXMgYWxzbyBhIGNvbmNlcm5pbmcgZGlmZmVyZW5jZSBpbiB5ZWFybHkgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZXMgYmV0d2VlbiB0aGUgdHdvIHJlZ2lvbnMuIERlcGVuZGluZyBvbiBob3cgaW1wb3J0YW50IHllYXIgZWZmZWN0cyBhcHBlYXItIHdlIG1heSBuZWVkIHRvIHRyaW0gdGhlIGRhdGEgZm9yIGJldHRlciBjb21wYXJpc29ucy4KCkJ5IG1vbnRoLCB3ZSBzZWUgdGhhdCBBdWd1c3QgY29udGFpbnMgc2FtcGxlcyBmcm9tIGFsbCByZWdpb25zLiBKdW5lIGlzIHRoZSBjZW50ZXIgZm9yIFNFQUsgYW5kIHRoZSBBbGV1dGlhbnMsIEp1bHkgZm9yIFNDQUssIGFuZCBBdWd1c3QgZm9yIENodWtjaGkvQmVhdWZvcnQuIEJlc3QgY29tcGFyaXNvbnMgZnJvbSB0aGlzIG1vbnRobHkgdmlldyBtYXkgYmUgYW4gQXVndXN0IChvciBsdW1wZWQgSnVseSArIEF1Z3VzdCkgY29tcGFyaXNvbiBvZiBhbGwgUmVnaW9ucy4gQWxzbywgYSBKdW5lIChvciBsdW1wZWQgSnVuZSB0aHJ1IEF1Z3VzdCkgY29tcGFyaXNvbiBvZiBHT0EgYW5kIHRoZSBBbGV1dGlhbnMgd291bGQgYmUgZ29vZC4gQW5kLCB3ZSBzaG91bGQgYmUgYWJsZSB0byBuaWNlbHkgY29tcGFyZSBTRUFLIGFuZCBTQ0FLIGZyb20gTWF5IHRvIFNlcHRlbWJlciwgcG90ZW50aWFsbHkgaW5jbHVkaW5nIEFwcmlsLgoKRm9yIG5vdywgd2UnbGwgaG9sZCBvZmYgb24gZXhjbHVkaW5nIGFueSBvZiB0aGUgZGF0YS4gSXQnbGwgYmUgYmV0dGVyIHRvIHJldmlzaXQgdGhlc2UgY29uc2lkZXJhdGlvbnMgYWZ0ZXIgZGVjaWRpbmcgd2hpY2ggcmVzZWFyY2ggcXVlc3Rpb25zIHRvIHRhY2tsZSwgc28gc3Vic2V0cyBvZiB0aGUgZGF0YSBjYW4gYmUgbWFkZSBzcGVjaWZpYyB0byBlYWNoIG9uZS4KCiMjIE1lc2ggU2l6ZSAmIFJlcGxpY2F0ZXMKCkxldCdzIG1ha2Ugc2ltaWxhciB2aXN1YWxzIGFzIGJlZm9yZSwgYnV0IG5vdyBmb2N1cyBvbiBNZXNoIFNpemUgYW5kIFJlcGxpY2F0ZXMgaW4gc3BhY2UgYW5kIHRpbWUuIEZpcnN0LCB3ZSBjYW4gcmUtbWFwIHRoZSBzYW1wbGVzIHRvIGNvbG9yIGJ5IE1lc2ggU2l6ZSBhbmQgc2l6ZSBvZiBwb2ludHMgcmVsYXRpdmUgUmVwbGljYXRlcyAobGFyZ2UgZG90cyA9IG1vcmUgcmVwbGljYXRlcykuCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgUGFsZXR0ZSBmdW5jdGlvbiB0byBjb2xvciBtYXJrZXJzCnBhbGV0dGUubWVzaCA9IGNvbG9yRmFjdG9yKHBhbGV0dGUgPSBicmV3ZXIucGFsKG4gPSB2aXNpdHMuMSRNZXNoU2l6ZSAlPiUgbl9kaXN0aW5jdCgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gJ1NwZWN0cmFsJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbiA9IGZhY3Rvcih2aXNpdHMuMSRNZXNoU2l6ZSkpCiMgTWFwCmxlYWZsZXQodmlzaXRzLjEpICU+JSAKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMobG5nID0gfkxvbiwgbGF0ID0gfkxhdCwKICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IH4oc3FydChSZXBsaWNhdGVzKjE1KSksCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWxldHRlLm1lc2goTWVzaFNpemUpLAogICAgICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbGV0dGUubWVzaChNZXNoU2l6ZSksCiAgICAgICAgICAgICAgICAgICBwb3B1cCA9IH5WaXNpdElELAogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UpICU+JQogIGFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsCiAgICAgICAgICAgIHBhbCA9IHBhbGV0dGUubWVzaCwgdmFsdWVzID0gfk1lc2hTaXplLAogICAgICAgICAgICB0aXRsZSA9ICJNZXNoIFNpemUgKG1tKSIsCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjc1KQpgYGAKCkkgaGF2ZSBhbiBpc3N1ZSBkaXNjZXJuaW5nIGFtb25nIHRoZSBzZXZlbiBkaWZmZXJlbnQgc2l6ZXMgc2luY2UgdGhvc2Ugd2FybWVyIGNvbG9ycyBkbyBub3QgZGl2ZXJnZSB3ZWxsLiBBbHRob3VnaCB0aGVyZSBhcmUgc29tZSBwYXR0ZXJucyB0byBtYWtlIG5vdGUgb2Y6IHRoZSBsYXJnZXN0IG1lc2ggc2l6ZSBvZiAxMi43IG9ubHkgb2NjdXJzIGluIGEgc21hbGwgYXJlYSBvZiBTRUFLLCB0aGUgMTAgbW0gc2FtcGxlcyBzaW1pbGFybHkgb25seSBvY2N1ciB3aXRoIHRoZSAxMi43IG1tIHNhbXBsZXMgKGxpa2VseSB0aGUgW0x1bmRzdHJvbSBldCBhbC4gMjAyMl0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMDcvczEyMjM3LTAyMi0wMTA1Ny14KSBnZWFyIGNvbXBhcmlzb24pLCBhbmQgdGhlIHNtYWxsZXN0IHNpemUgYXQgMyBtbSBvbmx5IG9jY3VycyBpbiBDb29rIElubGV0LiBJIGRvbid0IHNlZSBhbnkgb2J2aW91cyBzcGF0aWFsIHBhdHRlcm5zIGluIFJlcGxpY2F0ZXMsIGFsdGhvdWdoIHRoaXMgbWF5IG5vdCBiZSB0aGUgYmVzdCB2aWV3IG9mIGl0LgoKTGV0J3Mgc2VlIHRoZSBmcmVxdWVuY3kgb2Ygc2FtcGxlcyBmb3IgYm90aCB2YXJpYWJsZXM6CgpgYGB7cn0KIyBUYWJsZSB2aWV3CnRhYmxlKHZpc2l0cy4xJE1lc2hTaXplKQp0YWJsZSh2aXNpdHMuMSRSZXBsaWNhdGVzKQpgYGAKClRoZXJlIGFyZSBtb3JlIDEyLjcgbW0gc2FtcGxlcyB0aGFuIEkgd291bGQgaGF2ZSBndWVzc2VkIHdoaWNoIGlzIGEgc2hhbWUgYmVjYXVzZSBpZiB0aGV5IGFyZSBjb21wbGV0ZWx5IGRpZmZlcmVudCB0aGVuIHdlIGxvc2UgYSBsb3Qgb2Ygc2FtcGxlcy4gSSBhbSB3b25kZXJpbmcgaWYgc2l6ZXMgYXJlIGFjY3VyYXRlLSBJIHdvdWxkIHRoaW5rIHRoYXQgMyBtbSBhbmQgMy4yIG1tIGFyZSBlZmZlY3RpdmVseSBzaW1pbGFyIGluIHByYWN0aWNlLiBJIGFtIGFsc28gd29uZGVyaW5nIGlmIHNvbWUgcHJvamVjdHMgcmVwb3J0LCBzYXkgMyBtbSBpbnN0ZWFkIG9mIDMuMiBtbSwgYmVjYXVzZSBvZiByb3VuZGluZy4gSSB3b3VsZCBhc3N1bWUgdGhhdCB0aGUgbmV0cyB1c2VkIHdlcmUgbWFudWZhY3R1cmVkIGluIHRoZSBVUywgd2hpY2ggd291bGQgbWVhbiB0aGF0IHNwZWNpZmljYXRpb25zIGFyZSBnaXZlbiBpbiBzdGFuZGFyZCBub3QgbWV0cmljLiBMZXQncyBkbyBhIHF1aWNrIGNoZWNrIG9uIGhvdyB0eXBpY2FsIG1lc2ggc2l6ZXMgY29udmVydCBmcm9tIGluY2hlcyB0byBtaWxsaW1ldGVycy4KCmBgYHtyfQojIEZ1bmN0aW9uIGJhc2VkIG9uIGluY2ggdG8gbWlsbGltZXRlciBjb252ZXJzaW9uCmluX3RvX21tID0gZnVuY3Rpb24gKHgpIHsKICByZXR1cm4oeSA9IDI1LjQgKiB4KQp9CgojIFR5cGljYWwgbWVzaCBzaXplcyBpbiBpbmNoZXMKc2l6ZXMgPSBjKCgxLzgpLCAoMS80KSwgKDMvOCksICgxLzIpLCAoNS84KSwgKDMvNCkpCgojIENvbnZlcnQgdG8gbWlsbGltZXRlcnMKaW5fdG9fbW0oc2l6ZXMpCmBgYAoKVGhlcmUgaXMgb2J2aW91c2x5IHNvbWUgZnVubnkgcm91bmRpbmcgaGFwcGVuaW5nIGluIHRoZSBkYXRhLiBJIGRvIG5vdCBzZWUgYW4gaXNzdWUgYnkgbHVtcGluZyBtZXNoIHNpemVzIHRoYXQgYXJlIHdpdGhpbiBvbmUgbWlsbGltZXRlci4gRXZlbiBpZiB0aGUgbmV0cyB3ZXJlIGFjdHVhbGx5IGRpZmZlcmVudCBieSBmcmFjdGlvbnMgb2YgYSBtaWxsaW1ldGVyLCBJIGRvbid0IHRoaW5rIGl0IHdvdWxkIGFmZmVjdCB0aGUgc2VsZWN0aXZpdHkgb2YgZmlzaGVzIGFsbCB0aGF0IG11Y2gtIGVzcGVjaWFsbHkgY29uc2lkZXJpbmcgdGhhdCBtb3N0IG9mIHRoZXNlIHJlc2VhcmNoZXJzIHdlcmUgY2FwdHVyaW5nIGZpc2ggdG8gYmUgbWVhc3VyZWQgdG8gdGhlIG5lYXJlc3QgbWlsbGltZXRlci4KCkxldCdzIHNlZSB0aGF0IG1hcCBhZ2FpbiB3aXRoIHRoaXMgaW4gbWluZDoKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBQYWxldHRlIGZ1bmN0aW9uIGZvciBiaW5uZWQgc2l6ZXMKcGFsZXR0ZS5tZXNoLmJpbiA9IGNvbG9yQmluKHBhbGV0dGUgPSBicmV3ZXIucGFsKG4gPSA0LCBuYW1lID0gJ1NwZWN0cmFsJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb21haW4gPSB2aXNpdHMuMSRNZXNoU2l6ZSAlPiUgdW5pcXVlKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5zID0gIGMoMCwgNCwgNywgMTEsIDEzKSkKIyBNYXAKbGVhZmxldCh2aXNpdHMuMSkgJT4lIAogIGFkZFRpbGVzKCkgJT4lCiAgYWRkQ2lyY2xlTWFya2VycyhsbmcgPSB+TG9uLCBsYXQgPSB+TGF0LAogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gfihzcXJ0KFJlcGxpY2F0ZXMqMTUpKSwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnBhbGV0dGUubWVzaC5iaW4oTWVzaFNpemUpLAogICAgICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbGV0dGUubWVzaC5iaW4oTWVzaFNpemUpLAogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+VmlzaXRJRCwKICAgICAgICAgICAgICAgICAgIHN0cm9rZSA9IEZBTFNFKSAlPiUKICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLAogICAgICAgICAgICBjb2xvcnMgPSBjKHBhbGV0dGUubWVzaC5iaW4oMyksCiAgICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZS5tZXNoLmJpbig2KSwKICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlLm1lc2guYmluKDkpLAogICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUubWVzaC5iaW4oMTIpKSwKICAgICAgICAgICAgdmFsdWVzID0gfk1lc2hTaXplLAogICAgICAgICAgICB0aXRsZSA9ICJNZXNoIFNpemUgKG1tKSIsCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjc1LAogICAgICAgICAgICBsYWJlbHMgPSBjKCIzIG9yIDMuMiIsICI2IG9yIDYuNCIsICI5LjUgb3IgMTAiLCAiMTIuNyIpKQpgYGAKCk11Y2ggZWFzaWVyIHRvIHJlYWQhIEkgc2VlIHNvbWUgY29uY2VybmluZyBwYXR0ZXJucyB3ZSdsbCB3YW50IHRvIGludmVzdGlnYXRlIGZ1cnRoZXIgYXMgd2UgZ28uIFRoZSBtYWpvcml0eSBvZiBzYW1wbGVzIGFwcGVhciB0byBiZSB1c2luZyB0aGUgMy4yIG1tIHNpemUsIGluY2x1ZGluZyBib3RoIEFyY3RpYyBncm91cHMgdGhhdCBzZWVtIHRvIHVzZSBpdCBleGNsdXNpdmVseS4gVGhlcmUgaXMgYSBsYXJnZSBkZW5zaXR5IG9mIDYuNCBtbSBzYW1wbGVzIGluIE5vcnRoZXJuIFNFQUsgYW5kIHRocm91Z2hvdXQgdGhlIEFsZXV0aWFucy4gVGhlIHNhbWUgaXNzdWVzIGFyZSB2aXNpYmxlIGNvbmNlcm5pbmcgdGhlIHR3byBsYXJnZXIgbWVzaCBzaXplcy4gV2Ugc2hvdWxkIGRvIGEgY29tcGFyaXNvbiBvZiAzLjIgbW0gYW5kIDYuNCBtbSB0byBzZWUgaWYgdGhlcmUgYXJlIGFueSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiBjYXRjaC4KCldpdGggdGhlIHNpbXBsZXIgY29sb3Igc2NoZW1lLCBJIGFtIGFsc28gbm90aWNpbmcgdGhlIGRpZmZlcmVuY2UgaW4gUmVwbGljYXRlcyBhIGxpdHRsZSBlYXNpZXIuIEp1c3QgbG9va2luZyBhdCBHT0EgYW5kIEFsZXV0aWFuIHNhbXBsZXMsIEkgc2VlIHRoYXQgbWFueSBvZiB0aGUgNi40IG1tIHNhbXBsZXMgYXJlIGFsc28gbG93LVJlcGxpY2F0ZSBzYW1wbGVzLiBBbHRob3VnaCwgbWFueSBvZiBvdXIgc2FtcGxlcyBvbmx5IGNvbnRhaW4gb25lIHJlcGxpY2F0ZSBzbyB0aGlzIG1heSBqdXN0IGJlIHNvbWV0aGluZyBJJ20gc2VlaW5nIGFuZCBub3QgYWN0dWFsbHkgYSBjb25jZXJuLgoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IHRoZXNlIHZhcmlhYmxlcyBpbiBncmFwaGljYWwgZm9ybWF0LiBJJ2xsIGdvIGFoZWFkIGFuZCBhZ2dyZWdhdGUgc2ltaWxhciBtZXNoIHNpemVzIGFuZCByZS1jbGFzc2lmeSB0aGUgYm90aCB2YXJpYWJsZXMgYXMgZmFjdG9ycywgYW5kIGFkZCBpbiB2YXJpYWJsZXMgZm9yIHllYXIgYW5kIG1vbnRoLgoKYGBge3J9CnZpc2l0cy4yID0gbXV0YXRlKHZpc2l0cy4xLAogICAgICAgICAgICAgICAgICAjIFJlcGxpY2F0ZXMgYXMgYW4gb3JkZXJlZCBmYWN0b3IKICAgICAgICAgICAgICAgICAgUmVwbGljYXRlcyA9IGFzLm9yZGVyZWQoUmVwbGljYXRlcyksCiAgICAgICAgICAgICAgICAgICMgQ29tYmluZSBzaW1pbGFyIG1lc2ggc2l6ZXMgdG8gdGhlIHRlbnRoIGRlY2ltYWwKICAgICAgICAgICAgICAgICAgTWVzaFNpemUgPSBjYXNlX3doZW4oTWVzaFNpemUgPCA0IH4gMy4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNZXNoU2l6ZSA+IDQgJiBNZXNoU2l6ZSA8IDcgfiA2LjQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1lc2hTaXplID4gNyAmIE1lc2hTaXplIDwgMTEgfiA5LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1lc2hTaXplID09IDEyLjcgfiAxMi43KSAlPiUKICAgICAgICAgICAgICAgICAgICBhcy5vcmRlcmVkKCkpICU+JQogICMgQWRkIHRlbXBvcmFsIHZhcmlhYmxlcwogIGxlZnRfam9pbihzZWxlY3QodGltZXMsIFZpc2l0SUQsIFllYXIsIE1vbnRoLCBXZWVrLCBEYXkpLCBieSA9ICJWaXNpdElEIikgJT4lCiAgIyBXZWVrIGFzIGFuIG9yZGVyZWQgZmFjdG9yIChtb250aCBpcyBhbHJlYWR5IGFuIG9yZGVyZWQgZmFjdG9yKQogIG11dGF0ZShXZWVrID0gYXMub3JkZXJlZChXZWVrKSkKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgU2FtcGxlcyBieSBNZXNoU2l6ZSBhbmQgWWVhciwKZmlsdGVyKHZpc2l0cy4yLCBZZWFyID4gMTk4OSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IE1lc2hTaXplLCBjb2xvciA9IE1lc2hTaXplKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihzaXplID0gMC41LCBhbHBoYSA9IDAuNzUpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJ0ZXh0Iiwgdmp1c3QgPSAtMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIHsKICAgICAgICAgICAgICAgICByZXR1cm4oYyh5ID0gbWVkaWFuKHgpLCBsYWJlbCA9IGxlbmd0aCh4KSkpCiAgICAgICAgICAgICAgIH0pICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJXkiLAogICAgICAgICAgICAgICBkYXRlX2JyZWFrcyA9ICIyIHllYXJzIikgKwogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJNZXNoIFNpemUgKG1tKSIsCiAgICAgICB0aXRsZSA9ICJTYW1wbGVzIGJ5IFllYXIgYW5kIE1lc2ggU2l6ZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJFeGNsdWRpbmcgMTk3Njsgbm8uIHNhbXBsZXMgY2VudGVyZWQgb3ZlciBtZWRpYW4iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgojIFNhbXBsZXMgYnkgTW9udGggYW5kIE1lc2hTaXplLApmaWx0ZXIodmlzaXRzLjIsIFllYXIgPiAxOTg5KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNb250aCwgeSA9IE1lc2hTaXplLCBjb2xvciA9IE1lc2hTaXplKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihzaXplID0gMC41LCBhbHBoYSA9IDAuNzUpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJ0ZXh0Iiwgdmp1c3QgPSAtMywgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICBmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIHsKICAgICAgICAgICAgICAgICByZXR1cm4oYyh5ID0gbWVkaWFuKHgpLCBsYWJlbCA9IGxlbmd0aCh4KSkpCiAgICAgICAgICAgICAgIH0pKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNwZWN0cmFsIikgKwogIGxhYnMoeCA9ICJNb250aCIsIHkgPSAiTWVzaCBTaXplIChtbSkiLAogICAgICAgdGl0bGUgPSAiU2FtcGxlcyBieSBNb250aCBhbmQgTWVzaCBTaXplIiwKICAgICAgIHN1YnRpdGxlID0gIkV4Y2x1ZGluZyAxOTc2OyBuby4gc2FtcGxlcyBsYWJlbGxlZCBieSBtb250aCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpPdXIgc2FtcGxlcyBhcmUgZG9taW5hdGVkIGJ5IDMuMiBtbSBtZXNoIHNpemUuIEl0IGxvb2tzIHRvIGhhdmUgc29tZXdoYXQgZXZlbiBkaXN0cmlidXRpb24gYW1vbmcgeWVhcnMsIGJ1dCBzZWVtcyB0byBtaW1pYyB0aGUgZGVuc2l0eSBvZiBzYW1wbGluZyBpbiBTRUFLIGFuZCBTQ0FLIGluIHRoZSBsYXRlIDkwJ3MsIG1pZCAwMCdzLCBhbmQgbWlkIDEwJ3MuIFRoZSA2LjQgbW0gc2l6ZSBpcyBtdWNoIG1vcmUgc3BvcmFkaWMgd2l0aCBtYW55IHllYXJzIG1pc3Npbmcgc2FtcGxlcy4gV2UgYWxzbyBzZWUgdGhhdCBsYXJnZXIgbWVzaCBzaXplcyA5LjUgbW0gYW5kIDEyLjcgbW0gb25seSBvY2N1ciBpbiBhIGhhbmRmdWwgb2YgeWVhcnMgc3RhcnRpbmcgMjAxMy4gQnkgbW9udGgsIHdlIHNlZSBzaW1pbGFyIGRpc3RyaWJ1dGlvbnMgYW1vbmcgdGhlIG1lc2ggc2l6ZXMsIHdpdGggbW9zdCBzYW1wbGVzIG9jY3VycmluZyBpbiB0aGUgc3VtbWVyIChKdW4gLSBBdWcpIGFuZCBzaG91bGRlciBtb250aHMgKEFwciwgTWF5LCBTZXApLgoKYGBge3IgZWNobyA9IEZBTFNFfQojIFNhbXBsZXMgYnkgUmVwbGljYXRlcyBhbmQgWWVhciwKZmlsdGVyKHZpc2l0cy4yLCBZZWFyID4gMTk4OSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IFJlcGxpY2F0ZXMsIGNvbG9yID0gUmVwbGljYXRlcykpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjc1KSArCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAidGV4dCIsIHZqdXN0ID0gLTEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgZnVuLmRhdGEgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgcmV0dXJuKGMoeSA9IG1lZGlhbih4KSwgbGFiZWwgPSBsZW5ndGgoeCkpKQogICAgICAgICAgICAgICB9KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiV5IiwKICAgICAgICAgICAgICAgZGF0ZV9icmVha3MgPSAiMiB5ZWFycyIpICsKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiUmVwbGljYXRlcyIsCiAgICAgICB0aXRsZSA9ICJTYW1wbGVzIGJ5IFllYXIgYW5kIFJlcGxpY2F0ZXMiLAogICAgICAgc3VidGl0bGUgPSAiRXhjbHVkaW5nIDE5NzY7IG5vLiBzYW1wbGVzIGNlbnRlcmVkIG92ZXIgbWVkaWFuIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKIyBTYW1wbGVzIGJ5IFJlcGxpY2F0ZXMgYW5kIE1vbnRoLApmaWx0ZXIodmlzaXRzLjIsIFllYXIgPiAxOTg5KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNb250aCwgeSA9IFJlcGxpY2F0ZXMsIGNvbG9yID0gUmVwbGljYXRlcykpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjc1KSArCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAidGV4dCIsIHZqdXN0ID0gLTEsIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgZnVuLmRhdGEgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgcmV0dXJuKGMoeSA9IG1lZGlhbih4KSwgbGFiZWwgPSBsZW5ndGgoeCkpKQogICAgICAgICAgICAgICB9KSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpICsKICBsYWJzKHggPSAiTW9udGgiLCB5ID0gIlJlcGxpY2F0ZXMiLAogICAgICAgdGl0bGUgPSAiU2FtcGxlcyBieSBNb250aCBhbmQgUmVwbGljYXRlcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJFeGNsdWRpbmcgMTk3Njsgbm8uIHNhbXBsZXMgbGFiZWxsZWQgYnkgbW9udGgiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKSSBkbyBub3Qgc2VlIHRoZSB5ZWFybHkgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZXMgZGlmZmVyaW5nIGFsbCB0aGF0IG11Y2ggYW1vbmcgcmVwbGljYXRlcy4gRXhjZXB0IHRoYXQgdGhlIDYgLSA4IHJlcGxpY2F0ZXMgdGVuZCB0byBvY2N1ciBsYXRlciBpbiB0aGUgZGF0YXNldC4gSSBhbHNvIGRvIG5vdCBzZWUgYSBkaWZmZXJlbmNlIGluIGhvdyByZXBsaWNhdGVzIGRpc3RpcmJ1dGUgYW1vbmcgbW9udGhzLSBzaW1pbGFyIHRvIHdoYXQgd2UndmUgc2VlbiB0aGF0IG1vc3Qgc2FtcGxlcyBvY2N1ciBpbiBzdW1tZXIgYW5kIHNob3VsZGVyIG1vbnRocy4KCkxhc3QsIGxldCdzIHNlZSBhIGdyYXBoIG9mIE1lc2ggU2l6ZSB2cyBSZXBsaWNhdGVzOgoKYGBge3IgZWNobyA9IEZBTFNFfQpnZ3Bsb3QoZGF0YSA9IHZpc2l0cy4yLCBhZXMoeCA9IFJlcGxpY2F0ZXMsIHkgPSBNZXNoU2l6ZSkpICsKICBnZW9tX2ppdHRlcigpCmBgYAoKTm90aGluZyBuZXcgaGVyZSByZWFsbHkuCgojIyBQcmVwYXJpbmcgZGF0YSBmb3IgbmV4dCBzdGVwcwoKIyMjIFNwYXRpYWwgYXNwZWN0cwoKU3BhdGlhbCBlZmZlY3RzIGFyZSBwcm9iYWJseSB0aGUgbW9zdCB1bmtub3duIHRvIG1lIGFuZCBjb3VsZCB1c2UgZGVlcGVyIGludmVzdGlnYXRpb24uIFdlIGhhdmUgb2J2aW91cyByZWdpb25hbCBncm91cGluZyBvZiBzYW1wbGVzLCB3aXRoIGEgbGFyZ2UgbWFqb3JpdHkgb2NjdXJyaW5nIGluIFNFQUsgYW5kIFNDQUsuIFRoZXJlIGFyZSBpbnRlcmVzdGluZyBwb2NrZXRzIG9mIGRhdGEgZnJvbSB0aGUgQXJjdGljLCBCZXJpbmcgU2VhLCBhbmQgdGhlIEFsZXV0aWFucywgYnV0IGhvdyBjb21wYXJhYmxlIHRoZXNlICJyZWdpb25zIiBhcmUgbWF5IGJlIGNvbXBsaWNhdGVkIGJ5IGxvdyBzYW1wbGUgc2l6ZXMgYW5kIGNvbmZvdW5kaW5nIGZhY3RvcnMgKE1lc2ggU2l6ZSBvciBSZXBsaWNhdGVzKS4gSSB0aGluayB0YWNrbGluZyB0aGUgR29BIGlzIHRoZSBtb3N0IHVzZWZ1bCB0aGluZyB0byBkbyBhdCB0aGUgbW9tZW50IHNpbmNlIHRoZSBvdGhlciBhcmVhcyBhcmUgbXVjaCBtb3JlIGlzb2xhdGVkIGFuZCBkZW5zZWx5IHNhbXBsZWQuCgpRdWVzdGlvbnM6CgotICAgQmFzaWNhbGx5OiBob3cgc2hvdWxkIHdlIHRyZWF0IHNhbXBsZXMgZnJvbSBTRUFLLCBTQ0FLLCBhbmQgQWxldXRpYW5zPwotICAgQXJlIHRoZXJlIHJlZ2lvbmFsIGVmZmVjdHMgaW4gdGhlIEdvQT8KLSAgIERvIHRoZXNlIGVmZmVjdHMgYWxpZ24gd2l0aCBjdXJyZW50IHJlZ2lvbiBsYWJlbHMsIG9yIGlzIHRoZXJlIGEgbW9yZSBhcHByb3ByaWF0ZSBicmVhayBwb2ludD8KLSAgIENhbiB0aGUgQWxldXRpYW4gc2FtcGxlcyBiZSBncm91cGVkIHdpdGggdGhlIEdvQSwgb3IgaXMgaXQgbXVjaCB0b28gZGlmZmVyZW50PwotICAgQXJlIHRoZSB2YXJpb3VzIEFsZXV0aWFuIHNhbXBsZXMgYXBwcm9wcmlhdGUgdG8gYWdncmVnYXRlPwotICAgU2ltaWxhcmx5LCBhcmUgdGhlcmUgYXBwcm9wcmlhdGUgc3ViLXJlZ2lvbmFsIGdyb3VwcyB0aGF0IGNhbiBiZSBkZWZpbmVkIHdpdGhpbiBTRUFLIGFuZCBTQ0FLPwotICAgV2hhdCBzdWItcmVnaW9uYWwgZ3JvdXBpbmdzIG1ha2Ugc2Vuc2U/IFdoaWNoLCBpZiBhbnksIGFyZSBpbmZvcm1hdGl2ZT8KCkFmdGVyIHRoZXNlIHF1ZXN0aW9ucyBhcmUgYW5zd2VyZWQsIHdlIGNhbiByZWNvbW1lbmQgaG93IHRvIHRyZWF0IHNwYXRpYWwgYXNwZWN0cyBpbiB0aGUgZGF0YS4KCiMjIyBUZW1wb3JhbCBhc3BlY3RzCgpVbmxlc3Mgd2Ugd2FudCB0byBkbyBzb21lIGRpcmVjdCBjb21wYXJpc29ucyBiZXR3ZWVuIDE5NzYgYW5kIG90aGVyIHllYXJzIG9mIEthY2hlbWFrIEJheSwgaXQganVzdCBzZWVtcyB0b28gZmFyIGlzb2xhdGVkIGZyb20gdGhlIHJlc3Qgb2YgdGhlIGRhdGEgdG8gaW5jbHVkZSBpdCBpbiBhbmFseXNlcy4gSSB3aWxsIHRyeSB0byBhZGRyZXNzIHNlYXNvbmFsIGVmZmVjdHMgdXNpbmcgRGF5IG9mIFllYXIsIGJ1dCBtb3ZlIHRvIHdlZWtzIHRoZW4gbW9udGhzIGlmIG5lY2Vzc2FyeS4gV2Ugc2hvdWxkIGFsc28ga2VlcCBpbiBtaW5kIHRoYXQgQXByaWwvTWF5IGFuZCBTZXB0ZW1iZXIgcmVwcmVzZW50ICJzaG91bGRlciIgbW9udGhzIHRoYXQgYXJlIG11Y2ggbGVzcyBzYW1wbGVkIGNvbXBhcmVkIHRvIEp1bmUgLSBBdWd1c3QgcGVyaW9kLiBTb21lIHJlZ2lvbnMgbWF5IG5vdCBoYXZlIHNhbXBsZXMgZnJvbSBzaG91bGRlciBzZWFzb25zLCBzbyByZWR1Y2luZyB0aGUgZGF0YXNldCBtYXkgYmUgcmVxdWlyZWQgZGVwZW5kaW5nIG9uIHdoZXJlIHRoZSBjb21wYXJpc29ucyBhcmUgYmVpbmcgbWFkZS4KClF1ZXN0aW9uczoKCi0gICBXaGljaCBvZiBEYXksIFdlZWssIE1vbnRoIGlzIG1vc3QgaW5mb3JtYXRpdmUgYXMgc2Vhc29uYWxpdHk/CgpSZWNvbW1lbmRhdGlvbnM6CgotICAgUmVtb3ZlIDE5NzYgZGF0YQotICAgUmVtb3ZlIG1vbnRocyBvdXRzaWRlIG9mIEFwcmlsIC0gU2VwdGVtYmVyCi0gICBZZWFyIGFzIHJhbmRvbSBlZmZlY3QKLSAgIFNlYXNvbmFsaXR5IGFzIGZpeGVkIGVmZmVjdAoKIyMjIE1lc2ggU2l6ZQoKT3VyIDMuMiBtbSBzYW1wbGVzIGFyZSB0aGUgbW9zdCByZXByZXNlbnRlZCBtZXNoIHNpemUgb2NjdXJyaW5nIGluIGFsbCB5ZWFycyBvZiBkYXRhLiBUaGUgNi40IG1tIHNhbXBsZXMgYXJlIHRoZSBuZXh0IG1vc3QgZnJlcXVlbnQgYnV0IG9jY3VyIHNwb3JhZGljYWxseSBmcm9tIDE5OTktMjAwMywgMjAwNi0yMDA4LCAyMDExLTIwMTMsIGFuZCAyMDE3LiBUaGUgb3RoZXIgdHdvIHNpemVzIGFyZSB0aGUgbGVhc3QgZnJlcXVlbnQgYW5kIG9jY3VyIGluIGxhdGVyIHllYXJzIG9mIHRoZSBkYXRhc2V0IHN0YXJ0aW5nIGluIDIwMTMuIEJ5IG1vbnRoLCB3ZSBzZWUgYSBzaW1pbGFyIHRyZW5kIGFzIG90aGVyIHZhcmlhYmxlcyB3aGVyZSBtb3N0IHNhbXBsZXMgb2NjdXIgaW4gSnVuIC0gQXVnIG5vIG1hdHRlciB0aGUgbWVzaCBzaXplLgoKUXVlc3Rpb25zOgoKLSAgIElzIHRoZXJlIGEgc2lnbmlmaWNhbnQgZ2VhciBlZmZlY3QgYW1vbmcgbWVzaCBzaXplcz8gSW4gcGFydGljdWxhciBsb29raW5nIGF0IDMuMiBtbSB2cyA2LjQgbW0KClJlY29tbWVuZGF0aW9ucwoKLSAgIERyb3AgOS41IG1tIGFuZCAxMC43IG1tIHNpemVzIChsaWtlbHkgY29uZm91bmRlZCBieSBpc29sYXRlZCByZWdpb25hbCBlZmZlY3RzKQotICAgTWVzaCBzaXplIGFzIGZpeGVkIGVmZmVjdAoKIyMjIFJlcGxpY2F0ZXMKClNvbWV0aGluZyB0aGF0J3MgYmVlbiBvYnZpb3VzIGlzIHRoZSBoaWdoIGRlbnNpdHkgb2Ygc2FtcGxlcyB3aXRoIDEgb3IgMiByZXBsaWNhdGVzLiBJIHdvdWxkIGV4cGVjdCBhIGxhcmdlciB2YXJpYWJpbGl0eSBpbiBjYXRjaCByZXNwb25zZSBiZXR3ZWVuIG9uZS90d28gcmVwbGljYXRlIHNhbXBsZXMgdnMgdGhyZWUgb3IgbW9yZSByZXBsaWNhdGUgc2FtcGxlcy4gVGhlcmUgZG9lc24ndCBzZWVtIHRvIGJlIG11Y2ggb2YgYSBkaWZmZXJlbmNlIGluIHllYXJseSBzcHJlYWQgb2YgcmVwbGljYXRlcywgZXhjZXB0IHdoZW4gbG9va2luZyBhdCBzYW1wbGUgd2l0aCBmaXZlIG9yIG1vcmUgcmVwbGljYXRlcy4gU2ltaWxhcmx5IGJ5IG1vbnRoLCB3ZSBmaW5kIG1vc3Qgb2Ygb3VyIHNhbXBsZXMgdG8gb2NjdXIgaW4gSnVuIC0gQXVnIG5vIG1hdHRlciB0aGUgbnVtYmVyIG9mIHJlcGxpY2F0ZXMuCgpRdWVzdGlvbnMKCi0gICBDYW4gd2UgZXN0aW1hdGUgdGhlIG51bWJlciBvZiByZXBsaWNhdGVzIHRoYXQgcmVzdWx0cyBpbiBhbiBpbmZvcm1hdGl2ZSBzYW1wbGU/IElPVywgaXMgdGhlcmUgYW4gaWRlYWwgbnVtYmVyIG9mIHJlcGxpY2F0ZXMgKGUuZy4sIDMpIGJleW9uZCB3aGljaCB3ZSBkbyBub3QgZ2FpbiBhbnkgbW9yZSBtZWFuaW5nZnVsIGluZm9ybWF0aW9uPwoKUmVjb21tZW5kYXRpb25zCgotICAgTnVtYmVyIG9mIHJlcGxpY2F0ZXMgYXMgZml4ZWQgZWZmZWN0Ci0gICBTdGFuZGFyZGl6ZSBzYW1wbGVzIGJ5IG51bWJlciBvZiByZXBsaWNhdGVzLCBpLmUuLCBhdmVyYWdlIGNhdGNoIHBlciB2aXNpdAotICAgU3RhbmRhcmRpemUgc2FtcGxlcyBieSBhbm90aGVyIGVzdGltYXRlLCBlLmcuLCBzYW1wbGUgY29tcGxldGVuZXNzIG9yIHNwZWNpZXMgYWNjdW11bGF0aW9uIChpZiBuZWVkZWQpCi0gICBXZWlnaHQgc2FtcGxlcyBieSBob3cgbXVjaCBpbmZvcm1hdGlvbiBvbiBhdmVyYWdlIGVhY2ggbGV2ZWwgb2YgUmVwbGljYXRlcyBwcm92aWRlcyAoaWYgbmVlZGVkKQoKIyMgRml4aW5nIGRhdGEgb2JqZWN0cyBhbmQgY2xlYW4gdXAKCkxhc3QgdGhpbmcgd2UnbGwgaXMgZml4IG91ciB2aXNpdHMgZGF0YSBiYXNlZCBvbiBvdXIgcmVjb21tZW5kYXRpb25zIGFmdGVyIEVEQS4gV2UnbGwgc2F2ZSBhbiBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBkYXRhIGluIGNhc2Ugd2Ugd2FudCBpdCBmb3IgZnV0dXJlIGFuYWx5c2VzLgoKYGBge3J9CiMgQ3JlYXRlIGEgbmV3IHZpc2l0cyBvYmplY3QgY29udGFpbmluZyBhIHN1YnNldCBvZiB0aGUgZnVsbCBkYXRhCnZpc2l0cyA9IHZpc2l0cy4yICU+JQogICMgRmlsdGVyIHRlbXBvcmFsIGluZm86IHJlbW92ZSB5ZWFyIDE5NzYgYW5kIG1vbnRocyBvdXRzaWRlIG9mIEFwcmlsIC0gU2VwdGVtYmVyCiAgZmlsdGVyKFllYXIgPiAxOTgwKSAlPiUKICBmaWx0ZXIoTW9udGggPiAiTWFyIiAmIE1vbnRoIDwgIk9jdCIpICU+JQogICMgRmlsdGVyIG1lc2ggc2l6ZTogcmVtb3ZlIDkuNSBtbSBhbmQgMTAuNyBtbQogIGZpbHRlcihNZXNoU2l6ZSA8ICc5LjUnKSAlPiUKICAjIFJlLW9yZGVyIGZpbHRlcmVkIGZhY3RvcnMgdG8gbWF0Y2ggcmVkdWNlZCBsZXZlbHMKICBtdXRhdGUoTW9udGggPSBtb250aChEYXRlKSAlPiUgYXNfZmFjdG9yKCksCiAgICAgICAgIFdlZWsgPSB3ZWVrKERhdGUpICU+JSBhcy5vcmRlcmVkKCksCiAgICAgICAgIE1lc2hTaXplID0gTWVzaFNpemUgJT4lIGFzLmNoYXJhY3RlcigpICU+JSBhcy5vcmRlcmVkKCkpCgojIEtlZXAgYSBmdWxsIHZpc2l0cyBkYXRhIG9iamVjdCBhcyBhbm90aGVyIG9iamVjdAp2aXNpdHMuYWxsID0gdmlzaXRzLjIKCiMgUmVtb3ZlIHVud2FudGVkIG9iamVjdHMgaW4gZW52aXJvbm1lbnQKcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCdldmVudHMnLCAnY2F0Y2gnLCAndmlzaXRzJywgJ3Zpc2l0cy5hbGwnKV0pCgojIFJlc2V0IGRpcmVjdG9yeQp3ZCA9IGhlcmUoKQpkaXJzID0gd2QgJT4lIGxpc3QuZmlsZXMoKSAlPiUgc3RyX3N1YnNldChwYXR0ZXJuID0gIl5SRUFETUV8XkxJQ0VOU0V8Lm1kJHwuUnByb2okIiwgbmVnYXRlID0gVFJVRSkKZm9yIChpIGluIHNlcV9hbG9uZyhkaXJzKSkgewogIG5hbWUgPSBzdHJfcmVwbGFjZV9hbGwoZGlyc1tpXSwgIl4iLCAiZGlyLiIpCiAgcGF0aCA9IHN0cl9yZXBsYWNlX2FsbChkaXJzW2ldLCAiXiIsIHN0cl9jKHdkLCAiLyIpKQogIGFzc2lnbihuYW1lLCBwYXRoKQogIHJtKHBhdGgsIGkpCn0KYGBgCgojIEV4cGxvcmluZyBjYXRjaCBkYXRhCgojIyBTdW1tYXJ5IG9mIGNhdGNoCgpTaW5jZSB3ZSd2ZSByZWR1Y2VkIG91ciBzYW1wbGVzIGJhc2VkIG9uIGVhcmxpZXIgRURBLCB3ZSBuZWVkIHRvIHVwZGF0ZSBvdXIgY2F0Y2ggc2FtcGxlcyB0byByZWZsZWN0IHRoaXMuIFRoaXMgYWxzbyByZXF1aXJlcyBzdWJzZXR0aW5nIHRoZSBldmVudHMtbGV2ZWwgZGF0YSBvYmplY3QuCgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CiMgS2VlcCBhIGZ1bGwgdmVyc2lvbiBvZiB0aGUgZXZlbnRzIGRhdGEKZXZlbnRzLmFsbCA9IGV2ZW50cwojIENyZWF0ZSBhIHZlY3RvciBjb250YWluaW5nIHRoZSByZWR1Y2VkIGxpc3Qgb2YgdmlzaXRzCnZpc2l0cy52ZWMgPSB2aXNpdHMkVmlzaXRJRCAlPiUgdW5pcXVlKCkKIyBTdWJzZXQgdGhlIGV2ZW50cyBvYmplY3QKZXZlbnRzID0gZmlsdGVyKGV2ZW50cy5hbGwsIFZpc2l0SUQgJWluJSB2aXNpdHMudmVjKQpgYGAKClNpbWlsYXIgdG8gb3VyIHZpc2l0cyBvYmplY3QsIHdlJ2xsIGNyZWF0ZSBhIHdvcmtpbmcgdmVyc2lvbiBvZiBvdXIgY2F0Y2ggZGF0YSBidXQga2VlcCB0aGUgdmVyc2lvbiB0aGF0IGNvbnRhaW5zIGFsbCBpbmZvLgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KIyAjIEtlZXAgYSBmdWxsIHZlcnNpb24gb2YgdGhlIGNhdGNoIGRhdGEsIGFuZCByZW1vdmUgJ2NhdGNoJyBpZiBpdCdzIGluIHRoZSBlbnZpcm9ubWVudCwKaWYgKCJjYXRjaCIgJWluJSBscygpKSBhc3NpZ24oImNhdGNoLmFsbCIsIGNhdGNoKQppZiAoImNhdGNoIiAlaW4lIGxzKCkpIHJtKGNhdGNoKQoKIyBDcmVhdGUgYSB2ZWN0b3IgY29udGFpbmluZyB0aGUgcmVkdWNlZCBsaXN0IG9mIGV2ZW50cwpldmVudHMudmVjID0gZXZlbnRzJEV2ZW50SUQgJT4lIHVuaXF1ZSgpCiMgU3Vic2V0IHRoZSBjYXRjaCBkYXRhLCBhbmQgc3RhcnQgYSB3b3JraW5nIHZlcnNpb24gb2YgY2F0Y2gKY2F0Y2guMCA9IGZpbHRlcihjYXRjaC5hbGwsIEV2ZW50SUQgJWluJSBldmVudHMudmVjKQpgYGAKCk5vdyB3ZSBoYXZlIGEgc3Vic2V0dGVkIGNhdGNoIGRhdGEsIGxldCdzIHRha2UgYSBsb29rIGF0IHdoYXQncyB0aGVyZToKCmBgYHtyfQpza2ltcjo6c2tpbShjYXRjaC4wKQpgYGAKCkxvb2tpbmcgYXQgb3VyIGNoYXJhY3RlciBkYXRhLCB3ZSBzaG91bGQgZ28gYWhlYWQgYW5kIHJlbW92ZSBjb21tb24gbmFtZXMgc2ltcGx5IHRvIHJlZHVjZSBjbHV0dGVyLiBMZW5ndGhUeXBlIGlzIG5vdCB2ZXJ5IHVzZWZ1bCBhbmQgaXMgbWlzc2luZyBxdWl0ZSBhIGZldyBvYnNlcnZhdGlvbnMtIHdlJ2xsIGRyb3AgdGhpcyB0b28uIFdlIGtuZXcgTGlmZVN0YWdlIHdhcyBhbiBpc3N1ZSB3aGVuIHdlIGRpZCBvdXIgd3JhbmdsaW5nIHN0ZXBzLiBXZSBjYW4ga2VlcCBpdCBmb3Igbm93LCBidXQgbGlrZWx5IHdvbid0IHVzZSBpdCB0aWwgd2F5IGxhdGVyLiBIb3BlZnVsbHksIHdlIGNhbiBpbmZlciBMaWZlU3RhZ2UgZG93biB0aGUgcm9hZCBieSB1c2luZyB0aGUgbGVuZ3RoIGluZm9ybWF0aW9uLgoKTGV0J3MgYWRkIG91ciBWaXNpdElEIHZhcmlhYmxlIHNvIHdlIGFuYWx5c2Ugb3VyIGNhdGNoIGF0IHRoZSBzYW1wbGUgbGV2ZWwgKGluc3RlYWQgb2YgcmVwbGljYXRlKS4KCmBgYHtyfQpjYXRjaC4xID0gY2F0Y2guMCAlPiUKICAjIEFkZCBWaXNpdElEcwogIGxlZnRfam9pbihzZWxlY3QoZXZlbnRzLCBWaXNpdElELCBFdmVudElEKSwgYnkgPSAiRXZlbnRJRCIpICU+JQogICMgUmVtb3ZlIHVud2FudGVkIHBhcmFtZXRlcnMKICBzZWxlY3QoLWMoU3BfQ29tbW9uTmFtZSwgRmFtX0NvbW1vbk5hbWUsIExlbmd0aFR5cGUpKSAlPiUKICAjIFRpZHkgcGFyYW1ldGVycwogIHNlbGVjdChWaXNpdElELCBFdmVudElELAogICAgICAgICBGYW1fU2NpZW50aWZpY05hbWUsIEdlbl9TY2llbnRpZmljTmFtZSwgU3BfU2NpZW50aWZpY05hbWUsCiAgICAgICAgIENvdW50LCBMZW5ndGggPSBMZW5ndGhfbW0sIExpZmVTdGFnZSkKYGBgCgojIyBDYWxjdWxhdGUgbWV0cmljcyBvZiBjYXRjaAoKIyMjIE9jY3VycmVuY2UgYW5kIHJhcmUgdGF4YQoKUHJldmlvdXNseSBpbiB0aGUgd3JhbmdsZSBzdGVwLCB3ZSBkZWZpbmVkIHJhcmUgYXMgb2NjdXJyaW5nIGluIGxlc3MgdGhhbiAwLjI1JSBvZiBzYW1wbGVzLiBIb3dldmVyLCB3ZSBtYXkgc3RhcnQgd2l0aCBhIG1vcmUgY29uc2VydmF0aXZlIGFwcHJvYWNoIHRvIHNlZSBpZiByZW1vdmluZyBtb3JlIHJhcmUgc3BlY2llcyBpcyBuZWNlc3NhcnkuIEl0IG1ha2VzIHNlbnNlIHRvIG1lIHRvIHJlbW92ZSBzcGVjaWVzIHdpdGggb25seSAxIG9yIDIgb2NjdXJyZW5jZXMgZm9yIG5vdy4gVGhpcyBpcyBlcXVpdmFsZW50IHRvIHJlbW92aW5nIHNwZWNpZXMgb2NjdXJyaW5nIGluIGxlc3MgdGhhbiAwLjE1JSBvZiBzYW1wbGVzLgoKYGBge3J9CiMgQ3JlYXRlIGEgdGliYmxlIGZvciBzcGVjaWVzIG9jY3VycmVuY2VzCnNwLm9jY3VyID0gY2F0Y2guMSAlPiUgCiAgIyBGb3IgZWFjaCBzcGVjaWVzIHdpdGhpbiBlYWNoIHZpc2l0LCBQcmVzZW5jZSA9IDEKICBzdW1tYXJpc2UoUHJlc2VuY2UgPSBuX2Rpc3RpbmN0KFNwX1NjaWVudGlmaWNOYW1lKSwgLmJ5ID0gYyhWaXNpdElELCBTcF9TY2llbnRpZmljTmFtZSkpICU+JQogICMgRm9yIGVhY2ggc3BlY2llcywgdG90YWwgdGhlIG51bWJlciBvZiBwcmVzZW5jZXMKICBzdW1tYXJpc2UoT2NjdXJyZW5jZSA9IHN1bShQcmVzZW5jZSksIC5ieSA9IFNwX1NjaWVudGlmaWNOYW1lKSAlPiUKICAjIENhbGN1bGF0ZSBvY2N1cnJlbmNlIGFzIGEgcGVyY2VudGFnZQogIG11dGF0ZShQZXJjX09jY3VycmVuY2UgPSByb3VuZChPY2N1cnJlbmNlIC8gbl9kaXN0aW5jdChldmVudHMkVmlzaXRJRCkgKiAxMDAsIDIpKSAlPiUKICAjIEFkZCByYXJlIGNhdGVnb3J5IChzdWJqZWN0IHRvIGNoYW5nZSkKICBtdXRhdGUoUmFyZSA9IGlmZWxzZShPY2N1cnJlbmNlIDwgMywgIlllcyIsICJObyIpKQoKIyBDcmVhdGUgYSB0aWJibGUgZm9yIHRvdGFsIHByZXNlbmNlcyBwZXIgc2FtcGxlCm4ub2NjdXIgPSBjYXRjaC4xICU+JSAKICAjIEZvciBlYWNoIHNwZWNpZXMgd2l0aGluIGVhY2ggdmlzaXQsIFByZXNlbmNlID0gMQogIHN1bW1hcmlzZShQcmVzZW5jZSA9IG5fZGlzdGluY3QoU3BfU2NpZW50aWZpY05hbWUpLCAuYnkgPSBjKFZpc2l0SUQsIFNwX1NjaWVudGlmaWNOYW1lKSkgJT4lCiAgIyBGb3IgZWFjaCB2aXNpdCwgdG90YWwgdGhlIG51bWJlciBvZiBwcmVzZW5jZXMKICBzdW1tYXJpc2Uobl9zcCA9IHN1bShQcmVzZW5jZSksIC5ieSA9IFZpc2l0SUQpCgojIENyZWF0ZSBhIHZlY3RvciBvZiB0aGUgcmFyZSBzcGVjaWVzCnJhcmUuc3BlY2llcyA9IGZpbHRlcihzcC5vY2N1ciwgUmFyZSA9PSAiWWVzIikgJT4lIHB1bGwoU3BfU2NpZW50aWZpY05hbWUpCmBgYAoKYGBge3J9CiMgUmVtb3ZlIHJhcmUgdGF4YSBhbmQgdXBkYXRlIHRoZSBjYXRjaCB0aWJibGUKY2F0Y2guMiA9IGZpbHRlcihjYXRjaC4xLCAhU3BfU2NpZW50aWZpY05hbWUgJWluJSByYXJlLnNwZWNpZXMpCmBgYAoKIyMjIEF2ZXJhZ2UgYWJ1bmRhbmNlIHBlciB2aXNpdAoKQmVjYXVzZSBvdXIgc2FtcGxlcyAodmlzaXRzKSBjb250YWluIGEgdmFyaWFibGUgbnVtYmVyIG9mIHJlcGxpY2F0ZXMgKGV2ZW50cyksIEkgZGVjaWRlIHRvIHVzZSBhbiBhdmVyYWdpbmcgbWV0aG9kIHRvIGNhbGN1bGF0ZSBhYnVuZGFuY2UuIEhlcmUsIHdlIHVzZSBhIHNpbXBsZSBtZWFuIChpLmUuLCB0b3RhbCBjb3VudCAvIG51bWJlciBvZiByZXBsaWNhdGVzKSB0aGVuIEkgcm91bmQgdG8gdGhlIG5lYXJlc3QgdXBwZXIgaW50ZWdlci4gTm90ZSB0aGF0IHRoaXMgcm91bmRpbmcgbWV0aG9kIGdpdmVzIG1vcmUgcmVwcmVzZW50YXRpb24gb2YgcmFyZXIgdGF4YS4gRm9yIGV4YW1wbGUsIHNheSB3ZSBoYXZlIGEgc2FtcGxlIHdpdGggdGhyZWUgcmVwbGljYXRlcyBhbmQgY2F1Z2h0IHNwZWNpZXMgWCBhdCAwLCAwLCBhbmQgMSBmcmVxdWVuY3kuIFdlIGdldCBhbiBhdmVyYWdlIG9mIDAuMzMgd2hpY2ggcmVzdWx0cyBpbiBhbiBhYnVuZGFuY2Ugb2YgMSBhZnRlciByb3VuZGluZyB1cC4gSW4gYW5vdGhlciBzY2VuYXJpbyBsZXQncyBzYXkgd2UgY2F0Y2ggc3BlY2llcyBZIGluIHRoZSBzYW1lIHNhbXBsZSBhdCAyMCwgMjIsIGFuZCA0MDAgZnJlcXVlbmN5LiBXZSBoYXZlIGFuIGF2ZXJhZ2Ugb2YgMTQ3LjMgcmVzdWx0aW5nIGluIGFuIGFidW5kYW5jZSBvZiAxNDggYWZ0ZXIgcm91bmRpbmcgdXAuIFRoaXMgaXMgb3VyIGZpcnN0IGluc3RhbmNlIG9mIGRhdGEgc3RhbmRhcmRpemF0aW9uLCBidXQgd2UgbWF5IHdhbnQgdG8gZnVydGhlciBzdGFuZGFyZGl6ZSBhbmQvb3IgdHJhbnNmb3JtIGFidW5kYW5jZSBkYXRhIGRlcGVuZGluZyBvbiBFREEuCgpgYGB7cn0KIyBDcmVhdGUgYSB0aWJibGUgZm9yIGF2ZyBzcCBhYnVuZGFuY2UgcGVyIHZpc2l0CmFidW4gPSBjYXRjaC4yICU+JQogIHNlbGVjdChWaXNpdElELCBFdmVudElELCBTcF9TY2llbnRpZmljTmFtZSwgQ291bnQpICU+JQogIHN1bW1hcmlzZShBYnVuZGFuY2UgPSAoc3VtKENvdW50KSAvIG5fZGlzdGluY3QoRXZlbnRJRCkpICU+JSBjZWlsaW5nKCksIC5ieSA9IGMoVmlzaXRJRCwgU3BfU2NpZW50aWZpY05hbWUpKQpgYGAKCmBgYHtyfQpza2ltcjo6c2tpbShzZWxlY3QoYWJ1biwgQWJ1bmRhbmNlKSkKYGBgCgojIyMgU2l6ZSBpbmZvcm1hdGlvbgoKYGBge3J9CiMgQ3JlYXRlIGEgdGliYmxlIGZvciBjb250YWluaW5nIGxlbmd0aCBkYXRhIHBlciBzcGVjaWVzIGFuZCB2aXNpdApzaXplID0gc2VsZWN0KGNhdGNoLjIsIFZpc2l0SUQsIEV2ZW50SUQsIFNwX1NjaWVudGlmaWNOYW1lLCBMZW5ndGgpCmBgYAoKIyMgRGl2ZXJzaXR5CgojIyMgQ2hvb3NpbmcgaW5kaWNlcwoKYGBge3J9CiMgQ3JlYXRlIGEgdGliYmxlIG9mIGRpdmVyc2l0eSBpbmRpY2VzIHBlciBzYW1wbGUKZGl2ZXJzaXR5ID0gYWJ1biAlPiUKICBncm91cF9ieShWaXNpdElEKSAlPiUKICBzdW1tYXJpc2UoUyA9IHNwZWNudW1iZXIoU3BfU2NpZW50aWZpY05hbWUpLCAjIFJpY2huZXNzCiAgICAgICAgICAgIEggPSBkaXZlcnNpdHkoQWJ1bmRhbmNlLCBpbmRleCA9ICJzaGFubm9uIiksICMgU2hhbm5vbgogICAgICAgICAgICAjIHExID0gZXhwKEgpLCAjIGV4cChTaGFubm9uKQogICAgICAgICAgICBEID0gZGl2ZXJzaXR5KEFidW5kYW5jZSwgaW5kZXggPSAic2ltcHNvbiIpLCAjIFNpbXBzb24KICAgICAgICAgICAgIyBxMiA9IGRpdmVyc2l0eShBYnVuZGFuY2UsIGluZGV4ID0gImludnNpbXBzb24iKSwgIyBJbnZlcnNlLVNpbXBzb24KICAgICAgICAgICAgSiA9IGRpdmVyc2l0eShBYnVuZGFuY2UsIGluZGV4ID0gInNoYW5ub24iKSAvIGxvZyhTKSkgIyBQaWVsb3UncyBldmVubmVzcwpgYGAKCiMjIyBQbG90IGRpdmVyc2l0eSBhY3Jvc3MgdmFyaWFibGVzCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IGRpdmVyc2l0eSBpbmRpY2VzCnBsb3RfZGl2ZXJzaXR5ID0gZnVuY3Rpb24oeCkgewogIGRhdCA9IHZpc2l0cyAlPiUKICAgIHNlbGVjdChWaXNpdElELCAhIXN5bSh4KSkgJT4lCiAgICBsZWZ0X2pvaW4oZGl2ZXJzaXR5LCBieSA9ICJWaXNpdElEIikKICBwbG90X2luZGljZXMgPSBmdW5jdGlvbihkYXQpIHsKICAgIHBsb3RfbGlzdCA9IGxpc3QoKQogICAgRC5pbmRpY2VzID0gbmFtZXMoZGF0KVszOjZdCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgoRC5pbmRpY2VzKSkgewogICAgICBwbHVjayhwbG90X2xpc3QsIEQuaW5kaWNlc1tpXSkgPSBnZ3Bsb3QoZGF0KSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9ICEhc3ltKHgpLCB5ID0gISFzeW0oRC5pbmRpY2VzW2ldKSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjUpCiAgICB9CiAgICBvdXQgPSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBwbG90X2xpc3QsCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIsIG5yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgIGNvbW1vbi5sZWdlbmQgPSBUUlVFKQogICAgcmV0dXJuKG91dCkKICB9CiAgcGxvdF9pbmRpY2VzKGRhdCkgJT4lIHJldHVybigpCn0KCiMgRGVmaW5lIHdoaWNoIHZhcmlhYmxlcyB0byBwbG90IGRpdmVyc2l0eSBhZ2FpbnN0IGFuZCBzYXZlIGFzIGEgdmVjdG9yIAp2YXJzID0gYygiUmVwbGljYXRlcyIsICJNZXNoU2l6ZSIsICJMb24iLCAiWWVhciIsICJNb250aCIpCgojIEZvciBlYWNoIGRlZmluZWQgdmFyaWFibGUsIGFycmFuZ2UgcGxvdHMgb2YgZGl2ZXJzaXR5Cm1hcCh2YXJzLCBzdXBwcmVzc01lc3NhZ2VzKHBsb3RfZGl2ZXJzaXR5KSkKYGBgCgojIyMgRGlmZmVyZW5jZXMgaW4gcmljaG5lc3MKCmBgYHtyfQojIFZpc3VhbGl6ZSByaWNobmVzcyBieSByZXBsaWNhdGVzCmxlZnRfam9pbih2aXNpdHMsIGRpdmVyc2l0eSwgYnkgPSAiVmlzaXRJRCIpICU+JQogIGJveHBsb3QoUyB+IFJlcGxpY2F0ZXMsIGRhdGEgPSAuKQoKIyByZW1vdmUgcmVwbGljYXRlcyA9IDksIDEwLCAxMiBiYyBvZiBzaW5nbGUgb2JzCnRtcCA9IGxlZnRfam9pbih2aXNpdHMsIGRpdmVyc2l0eSwgYnkgPSAiVmlzaXRJRCIpICU+JQogIG11dGF0ZShSZXBsaWNhdGVzID0gYXMubnVtZXJpYyhSZXBsaWNhdGVzKSkgJT4lCiAgZmlsdGVyKFJlcGxpY2F0ZXMgPCA5KQoKIyBhbmFseXNpcyBvZiB2YXJpYW5jZQphb3YuUy5yZXBzID0gYW92KFMgfiBhcy5mYWN0b3IoUmVwbGljYXRlcyksIGRhdGEgPSB0bXApCnN1bW1hcnkoYW92LlMucmVwcykKIyBwYWlyd2lzZSB0ZXN0ClR1a2V5SFNEKGFvdi5TLnJlcHMpICU+JSBicm9vbTo6dGlkeSgpICU+JSBzZWxlY3QoLXRlcm0pICU+JSBrbml0cjo6a2FibGUoZGlnaXRzID0gMykKIyByZXNpZHVhbHMKcmVzaWR1YWxzID0gcmVzaWR1YWxzKGFvdi5TLnJlcHMpCnBsb3QocmVzaWR1YWxzKQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KGFvdi5TLnJlcHMpCnBhcihtZnJvdyA9IGMoMSwgMSkpCiMgY2hlY2sgZm9yIGhvbW9nZW5laXR5CnNoYXBpcm8udGVzdChyZXNpZHVhbHMpCiMgcmVzdWx0OiB2aW9sYXRpb24gb2YgaG9tb2dlbmVpdHkKCiMga3J1c2thbC13YWxsaXMgdGVzdAprcnVza2FsLnRlc3QoUyB+IFJlcGxpY2F0ZXMsIGRhdGEgPSB0bXApCgojIG9uZSB3YXkgdC10ZXN0IG5vdCBhc3N1bWluZyBlcXVhbCB2YXJpYW5jZXMKb25ld2F5LnRlc3QoUyB+IFJlcGxpY2F0ZXMsIGRhdGEgPSB0bXApCiMgcGFpcndpc2UgdGVzdApyZXN1bHRzID0gcGFpcndpc2UudC50ZXN0KHRtcCRTLCB0bXAkUmVwbGljYXRlcywKICAgICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiQkgiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBvb2wuc2QgPSBGQUxTRSkKcmVzdWx0cwoKIyBwbG90IHQudGVzdCByZXN1bHRzCmdncGxvdCh0bXApICsKICBhZXMoeCA9IFJlcGxpY2F0ZXMsIHkgPSBTLCBncm91cCA9IFJlcGxpY2F0ZXMpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9zaWduaWYodGVzdCA9ICJ0LnRlc3QiLAogICAgICAgICAgICAgIGNvbXBhcmlzb25zID0gbGlzdChjKDEsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDIsIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDIsIDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDMsIDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDMsIDUpKSwKICAgICAgICAgICAgICB5X3Bvc2l0aW9uID0gYygzMywgMzYsIDM5LCA0MywgNDYpLAogICAgICAgICAgICAgIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFKQpgYGAKCiMjIFNwZWNpZXMgRURBIHBsb3RzIHsudGFic2V0IC50YWJzZXQtcGlsbHN9CgpgYGB7ciBldmFsID0gRkFMU0UsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShwcm9ncmVzc3IpCgojIEZ1bmN0aW9uIHRvIGNyZWF0ZSBlZGEgcGxvdHMgZm9yIHNwZWNpZXMKc3BlY2llc19wbG90cyA9IGZ1bmN0aW9uIChhYnVuLCBzaXplLCB2aXNpdHMpIHsKICAjIENyZWF0ZSBhIHZlY3RvciBjb250YWlpbmcgYWxsIHRoZSBzcGVjaWVzIG5hbWVzCiAgc3BlY2llcyA9IGFidW4kU3BfU2NpZW50aWZpY05hbWUgJT4lIHVuaXF1ZSgpICU+JSBzb3J0KCkKICAjIENyZWF0ZSBhIGxpc3Qgb2JqZWN0IHRvIGhvbGQgdGhlIHBsb3RzIGZvciBlYWNoIHNwZWNpZXMKICBwbG90X2xpc3QgPSBsaXN0KCkKICAjIFNldCBwcm9ncmVzcyBmdW5jdGlvbgogIHBiID0gcHJvZ3Jlc3NvcihhbG9uZyA9IHNwZWNpZXMpCiAgIyBMb29wIHRocm91Z2ggYWxsIHNwZWNpZXMKICBmb3IgKGkgaW4gMTpsZW5ndGgoc3BlY2llcykpIHsKICAgICMgUGxvdCAxOiBmcmVxdWVuY3kgb2YgYWJ1bmRhbmNlIGhpc3RvZ3JhbSAoc2NhbGVkIHRvIGRlbnNpdHkpIGFuZCBkZW5zaXR5IGxpbmUKICAgIHAxID0gZmlsdGVyKGFidW4sIFNwX1NjaWVudGlmaWNOYW1lID09IHNwZWNpZXNbaV0pICU+JQogICAgICBnZ3Bsb3QoKSArCiAgICAgIGFlcyh4ID0gQWJ1bmRhbmNlKSArCiAgICAgIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksIGJpbnMgPSA1MCkgKwogICAgICBnZW9tX2RlbnNpdHkoY29sID0gImJsdWUiKSArCiAgICAgIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAuNSwgMC4xLCAwLjEsIDAuMSwgdW5pdCA9ICJpbiIpKQogICAgIyBQbG90IDI6IGZyZXF1ZW5jeSBvZiBhYnVuZGFuY2UgaGlzdG9ncmFtLCBsb2cgdHJhbnNmb3JtZWQgKyAxCiAgICBwMiA9IGZpbHRlcihhYnVuLCBTcF9TY2llbnRpZmljTmFtZSA9PSBzcGVjaWVzW2ldKSAlPiUKICAgICAgZ2dwbG90KCkgKwogICAgICBhZXMoeCA9IGxvZyhBYnVuZGFuY2UgKyAxKSkgKwogICAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkpLCBiaW5zID0gNTApICsKICAgICAgZ2VvbV9kZW5zaXR5KGNvbCA9ICJibHVlIikgKwogICAgICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigwLjUsIDAuMSwgMC4xLCAwLjEsIHVuaXQgPSAiaW4iKSkKICAgICMgUGxvdCAzOiBsb2coQWJ1bmRhbmNlICsgMSkgYnkgTG9uZ2l0dWRlCiAgICBwMyA9IGxlZnRfam9pbihhYnVuLCBzZWxlY3QodmlzaXRzLCBWaXNpdElELCBMb24pLCBieSA9ICJWaXNpdElEIikgJT4lCiAgICAgIGZpbHRlcihTcF9TY2llbnRpZmljTmFtZSA9PSBzcGVjaWVzW2ldKSAlPiUKICAgICAgZ2dwbG90KCkgKwogICAgICBhZXMoeCA9IExvbiwgeSA9IGxvZyhBYnVuZGFuY2UgKyAxKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gcmFuZ2UodmlzaXRzJExvbikpICsKICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMC4xLCAwLjEsIDAuMSwgMC4xLCB1bml0ID0gImluIikpCiAgICAjIFBsb3QgNDogbG9nKEFidW5kYW5jZSArIDEpIGJ5IExhdGl0dWRlCiAgICBwNCA9IGxlZnRfam9pbihhYnVuLCBzZWxlY3QodmlzaXRzLCBWaXNpdElELCBMYXQpLCBieSA9ICJWaXNpdElEIikgJT4lCiAgICAgIGZpbHRlcihTcF9TY2llbnRpZmljTmFtZSA9PSBzcGVjaWVzW2ldKSAlPiUKICAgICAgZ2dwbG90KCkgKwogICAgICBhZXMoeCA9IGxvZyhBYnVuZGFuY2UgKyAxKSwgeSA9IExhdCkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gcmFuZ2UodmlzaXRzJExhdCkpICsKICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMC4xLCAwLjEsIDAuMSwgMC4xLCB1bml0ID0gImluIikpCiAgICAjIFBsb3QgNTogU2l6ZSBmcmVxdWVuY3kgaGlzdG9ncmFtIChzY2FsZWQgdG8gZGVuc2l0eSkgYW5kIGRlbnNpdHkgbGluZQogICAgcDUgPSBmaWx0ZXIoc2l6ZSwgU3BfU2NpZW50aWZpY05hbWUgPT0gc3BlY2llc1tpXSkgJT4lCiAgICAgIGdncGxvdCgpICsKICAgICAgYWVzKHggPSBMZW5ndGgpICsKICAgICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgYmlucyA9IDUwKSArCiAgICAgIGdlb21fZGVuc2l0eShjb2wgPSAicmVkIikgKwogICAgICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigwLjEsIDAuMSwgMC4xLCAwLjEsIHVuaXQgPSAiaW4iKSkKICAgICMgUGxvdCA2OiBTaXplIGJ5IERheSBvZiBZZWFyCiAgICBwNiA9IGxlZnRfam9pbihzaXplLCBzZWxlY3QodmlzaXRzLCBWaXNpdElELCBEYXkpLCBieSA9ICJWaXNpdElEIikgJT4lCiAgICBmaWx0ZXIoU3BfU2NpZW50aWZpY05hbWUgPT0gc3BlY2llc1tpXSkgJT4lCiAgICAgIGdncGxvdCgpICsKICAgICAgYWVzKHggPSBEYXksIHkgPSBMZW5ndGgpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IHJhbmdlKHZpc2l0cyREYXkpKSArCiAgICAgIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAuMSwgMC4xLCAwLjEsIDAuMSwgdW5pdCA9ICJpbiIpKQogICAgIyBGaW5kIHRoZSBudW1iZXIgb2Ygc2FtcGxlcyBhbmQgdG90YWwgYWJ1bmRhbmNlIGZvciBlYWNoIHNwZWNpZXMKICAgIG4gPSBmaWx0ZXIoYWJ1biwgU3BfU2NpZW50aWZpY05hbWUgPT0gc3BlY2llc1tpXSkgJT4lIG5fZGlzdGluY3QoKQogICAgY291bnQgPSBmaWx0ZXIoYWJ1biwgU3BfU2NpZW50aWZpY05hbWUgPT0gc3BlY2llc1tpXSkgJT4lIHN1bW1hcmlzZShuID0gc3VtKEFidW5kYW5jZSkpICU+JSBwbHVjaygxKQogICAgIyBBcnJhbmdlIHRoZSBwbG90cyBhbmQgbGFiZWwgd2l0aCBzcGVjaWVzIG5hbWUgYW5kIG51bWJlciBvZiBzYW1wbGVzCiAgICBvdXQgPSBnZ2FycmFuZ2UocDEsIHAyLAogICAgICAgICAgICAgICAgICAgIHAzLCBwNCwKICAgICAgICAgICAgICAgICAgICBwNSwgcDYsCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIsIG5yb3cgPSAzKSAlPiUKICAgICAgICBhbm5vdGF0ZV9maWd1cmUoZmlnLmxhYiA9IHN0cl9jKHNwZWNpZXNbaV0sICIsIHNhbXBsZXMgPSAiLCBuLCAiLCBhYnVuZGFuY2UgPSAiLCBjb3VudCwgc2VwID0gIiIpLAogICAgICAgICAgICAgICAgICAgICAgICBmaWcubGFiLnNpemUgPSAxNCkKICAgICMgU2F2ZSB0aGUgYXJyYW5nZWQgcGxvdHMgYXMgYSBuYW1lZCBsaXN0IGl0ZW0KICAgIHBsdWNrKHBsb3RfbGlzdCwgc3BlY2llc1tpXSkgPSBvdXQKICAgICMgU2lnbmFsIHByb2dyZXNzCiAgICBwYihtZXNzYWdlID0gcGFzdGUoIlBsb3R0aW5nICIsIHNwZWNpZXNbaV0pKQogIH0KICAjIE91dHB1dAogIHJldHVybihwbG90X2xpc3QpCn0KCiMgSWYgcGxvdCBsaXN0IGRvZXMgbm90IGV4aXN0IGluIHRoZSBlbnZpcm9ubWVudCwgcnVuIHRoZSBwbG90dGluZyBmdW5jdGlvbgppZiAoIWFueShscygpICVpbiUgInBsb3RfbGlzdCIpKSB7CiAgIyBQcm9ncmVzcyBiYXIgc2V0dGluZ3MKICBoYW5kbGVycygiY2xpIikKICAjIFNhdmUgcGxvdHMgdG8gYSBsaXN0LCB3aXRoIHByb2dyZXNzIGJhciBlbmFibGVkCiAgd2l0aF9wcm9ncmVzcyhwbG90X2xpc3QgPC0gc3BlY2llc19wbG90cyhhYnVuLCBzaXplLCB2aXNpdHMpKQp9CgojIEZ1bmN0aW9uIHRvIHNhdmUgZWFjaCBzcGVjaWVzIHBsb3QgYXMgYSBwbmcgaW4gYSBzdWJmb2xkZXIgaW4gdGhlIGRpcmVjdG9yeQpzYXZlX3Bsb3RfbGlzdCA9IGZ1bmN0aW9uIChscykgewogICMgQ3JlYXRlIGEgdmVjdG9yIGNvbnRhaW5pbmcgYWxsIHRoZSBzcGVjaWVzIG5hbWVzCiAgc3BlY2llcyA9IGFidW4kU3BfU2NpZW50aWZpY05hbWUgJT4lIHVuaXF1ZSgpICU+JSBzb3J0KCkKICAjIEZvciBlYWNoIHNwZWNpZXMsIHNhdmUgYSBmaWxlIGluIGEgZmlncyBzdWJmb2xkZXIKICBpd2FsayhzcGVjaWVzLCB+IGdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucGF0aChkaXIuZmlncywgInNwZWNpZXMgZWRhIiwgc3RyX2MoLngsICIucG5nIiwgc2VwID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90ID0gcGx1Y2sobHMsIC54KSwgZGV2aWNlID0gInBuZyIsIGNyZWF0ZS5kaXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDE1LCB3aWR0aCA9IDEwLCB1bml0cyA9ICJpbiIpLAogICAgICAgIC5wcm9ncmVzcyA9ICJTYXZpbmcgc3BlY2llcyBwbG90czoiKQp9CgojIElmIHRoZXJlIGFyZSBubyBzcGVjaWVzIHBsb3RzIHNhdmVkLCB0aGVuIHJ1biB0aGUgc2F2ZSBwbG90IGZ1bmN0aW9uCmlmIChsaXN0LmZpbGVzKGZpbGUucGF0aChkaXIuZmlncywgInNwZWNpZXMgZWRhIikpICU+JSBsZW5ndGgoKSA9PSAwKSB7CiAgc2F2ZV9wbG90X2xpc3QocGxvdF9saXN0KQp9CmBgYAoKIyMjIFdhbGxleWUgUG9sbG9jayB7LnVubnVtYmVyZWR9CgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGggPSAnMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGZpbGUucGF0aChkaXIuZmlncywgInNwZWNpZXMgZWRhIiwgIkdhZHVzIGNoYWxjb2dyYW1tdXMucG5nIikpCmBgYAoKIyMjIFN0YXJyeSBGbG91bmRlciB7LnVubnVtYmVyZWR9CgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGggPSAnMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGZpbGUucGF0aChkaXIuZmlncywgInNwZWNpZXMgZWRhIiwgIlBsYXRpY2h0aHlzIHN0ZWxsYXR1cy5wbmciKSkKYGBgCgojIyMgR3JlYXQgU2N1bHBpbiB7LnVubnVtYmVyZWR9CgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGggPSAnMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGZpbGUucGF0aChkaXIuZmlncywgInNwZWNpZXMgZWRhIiwgIk15b3hvY2VwaGFsdXMgcG9seWFjYW50aG9jZXBoYWx1cy5wbmciKSkKYGBgCgojIyMgUGFjaWZpYyBIZXJyaW5nIHsudW5udW1iZXJlZH0KCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aCA9ICcxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoZmlsZS5wYXRoKGRpci5maWdzLCAic3BlY2llcyBlZGEiLCAiQ2x1cGVhIHBhbGxhc2lpLnBuZyIpKQpgYGAKCiMjIyBDb2hvIFNhbG1vbiB7LnVubnVtYmVyZWR9CgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGggPSAnMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGZpbGUucGF0aChkaXIuZmlncywgInNwZWNpZXMgZWRhIiwgIk9uY29yaHluY2h1cyBraXN1dGNoLnBuZyIpKQpgYGAKCiMjIyBEb2xseSBWYXJkZW4gey51bm51bWJlcmVkfQoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoID0gJzEwMCUnfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhmaWxlLnBhdGgoZGlyLmZpZ3MsICJzcGVjaWVzIGVkYSIsICJTYWx2ZWxpbnVzIG1hbG1hLnBuZyIpKQpgYGAKCiMjIE1WIE9yZGluYXRpb25zCgojIyMgQ3JlYXRlIGNhdGNoIG1hdHJpeCBiYXNlZCBvbiBhdmVyYWdlIGFidW5kYW5jZXMKCmBgYHtyfQojIENyZWF0ZSBhIGRhdGEuZnJhbWUgaW4gc2FtcGxlIHggc3BlY2llcyBmb3JtYXQgKGUuZy4sIHZlZ2FuKQphYnVuLm1hdCA9IGFidW4gJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFNwX1NjaWVudGlmaWNOYW1lLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gQWJ1bmRhbmNlLAogICAgICAgICAgICAgIHZhbHVlc19maWxsID0gMCkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJWaXNpdElEIikKYGBgCgojIyMgU3RhbmRhcmRpemUgY2F0Y2gKCmBgYHtyfQojIHByZXNlbmNlL2Fic2VuY2UKcGEgPSBkZWNvc3RhbmQoYWJ1bi5tYXQsIG1ldGhvZCA9ICJwYSIpCgojIDR0aCByb290CnJ0NCA9IG11dGF0ZShhYnVuLm1hdCwgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiAueF4oMS80KSkpCgojIHJvYnVzdCBDTFIKcmNsciA9IGRlY29zdGFuZChhYnVuLm1hdCwgbWV0aG9kID0gInJjbHIiKQpgYGAKCiMjIyBDYWxjdWxhdGUgZGlzdGFuY2VzCgpgYGB7cn0KIyBKYWNjYXJkIGRpc3RhbmNlcyBvbiBQL0EgZGF0YQpqYWMgPSB2ZWdkaXN0KGFzLm1hdHJpeChwYSksIG1ldGhvZCA9ICJqYWNjYXJkIikKCiMgQnJheS1DdXJ0aXMgZGlzdGFuY2Ugb24gNHRoIHJ0IHRyYW5zZm9ybWVkIGRhdGEKYmMgPSB2ZWdkaXN0KGFzLm1hdHJpeChydDQpLCBtZXRob2QgPSAiYnJheSIpCgojIEV1Y2xpZGVhbiBkaXN0YW5jZSBvbiBSQ0xSIHRyYW5zZm9ybWVkIGRhdGEsIGkuZS4sIHJvYnVzdCBhaXRjaGlzb24gZGlzdGFuY2UKcmFpdCA9IHZlZ2Rpc3QoYXMubWF0cml4KHJjbHIpLCBtZXRob2QgPSAiZXVjbGlkZWFuIikKYGBgCgojIyMgT3JkaW5hdGlvbnMKCmBgYHtyIGV2YWwgPSBGQUxTRX0Kbm1kcy5qYWMgPSBtZXRhTURTKGphYykKcGxvdChubWRzLmphYywgdHlwZSA9ICJ0IikKCm5tZHMuYmMgPSBtZXRhTURTKGJjKQpwbG90KG5tZHMuYmMsIHR5cGUgPSAidCIpCgojIyBwbG90IHVzaW5nIHJkYSgpIGFiZCBiaXBsb3QoKQojIHBjYS5yY2xyID0gcmRhKGFzLm1hdHJpeChyY2xyKSkKIyBiaXBsb3QocGNhLnJjbHIsIGRpc3BsYXkgPSBjKCJzaXRlcyIsICJzcGVjaWVzIiksIHR5cGUgPSBjKCJ0ZXh0IiwgInBvaW50cyIpKQoKbWRzLnJjbHIgPSBtZXRhTURTKHJhaXQpCnBsb3QobWRzLnJjbHIsIHR5cGUgPSAidCIpCmBgYAoKIyMjIExvb2sgYXQgdGhlIG91dGxpZXIgc2FtcGxlCmBgYHtyfQpmaWx0ZXIodmlzaXRzLCBWaXNpdElEID09ICI4NDZfMjAxNS0wOC0xNSIpICU+JQogIGxlZnRfam9pbihjYXRjaC4yLCBieSA9ICJWaXNpdElEIikgJT4lCiAgZ2xpbXBzZSgpCmBgYAo=